Jump to content

_TCPFileTransfer.au3


delme
 Share

Recommended Posts

Hey, this is just a little (but useful) script that I had posted here awhile ago, I recently updated it as it had a few major issues, but now it should be working correctly. All the info on how to use this is in the function headers below and in the headers in the file, hope you guys find this useful. If you find any bugs please let me know. Please feel free to post your questions and opinions bellow :).

To start an interrupted transfer from where it encountered an error you would do this:

$i = _TCPFileRecv($sock, "Randomfile.exe")
;*Gets interupted*
$newoffset = @extended ;@extended would be used to get the number of bytes successfully written to the file if an error had occured
;You need to communicate the number of bytes that were successfully recorded to the sending script somehow to make sure they send the file from the right offset, else the file will get corrupted. Just use a simple tcp message for this
$i = _TCPFileRecv($sock, "Randomfile.exe", $newoffset) ;start writing the file from where you left off

Here is the folder with the script examples:

_TCPFileTransfer.zip

and here is the _TCPFileTransfer.au3 file alone:

_TCPFileTransfer.au3

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.6.0
 Author:         DELmE

 Function:
    _TCPFileRecv

Description:
    Receives a file being sent over a TCP connection

Parameters:
    sock                The TCP socket to be used
    rFile               The name of the file to save to
    offset = 0          The offset to start writing data to the file at (to be used if the transfer is somehow interrupted) default value is 0 (no offset)
    $DataSize = 1024    The number of bytes of data to be received per packet, default value is 1024

Return value:
    Success     _TCPFileRecv returns the number of bytes written to the file
    Failure     _TCPFileRecv returns 0 if the function failed and sets @error to the following:
        1 = Error opening the file
        2 = Failed to set offset
        3 = Failed to receive data on socket (invalid socket)
        4 = Unable to write data to the file
        Also sets @extended to the number of bytes of data that was successfully written to the file

#ce ----------------------------------------------------------------------------

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.6.0
 Author:         DELmE

 Function:
    _TCPFileSend

Description:
    Sends a file over a TCP connection

Parameters:
    sock                The tcp socket to be used
    sFile               The file to be sent
    offset = 0          The offset to start reading data from the file at (to be used if the transfer is somehow interrupted) default value is 0 (no offset)
    $DataSize = 1024    The number of bytes of data to be sent per packet, default value is 1024

Return value:
    Success     _TCPFileSend returns the number of bytes sent
    Failure     _TCPFileSend returns 0 if an error occurred and sets @error to the following:
        1 = The file does not exist
        2 = Failed to set offset
        3 = Failed to read data from file
        4 = Failed to send data through socket
        Also sets @extended to the number of bytes of data that was successfully sent

#ce ----------------------------------------------------------------------------

Updates:

[5/16/2010] Changed the code completely, can now handle files of all sizes and supports offsets.

Edit:

Thanks to Manadar and FireFox for their help :)

Edited by DELmE
Link to comment
Share on other sites

Ok, I had a look at the library after your desperate plee. : )

But be warned, the code definitely needs some attention if you want other programmers to be able to use the library without modifying it.

$TCPSend = TCPSend($TCPConn, $oFileRead)
        If $TCPSend = 0 Then
            $error = True
        Else
            $buff = BinaryMid ($oFileOpen, $TCPSend + 1, BinaryLen ($oFileOpen) - $TCPSend)
            Do
                $TCPSend = TCPSend($TCPConn, $buff)
                $buff = BinaryMid ($buff, $TCPSend + 1, BinaryLen ($buff) - $TCPSend)
            Until $buff = ""
        EndIf

I'm not sure if I fully understand how this works, but it seems to me that you're trying to send the entire file in one piece ( regardless of size ) first and if that fails you are sending it in chunks; Why not send it in chunks immediately? The benefit of chunks is that the application will not hang and you can check for errors during the transfer. If an error occurs you should be able to reconnect and continue the file transfer on a new socket.

$TCPRecv = TCPRecv($TCPAcc, 9999999)
;------------------------------^

Why 9999999? Numbers like this that make no sense and should be avoided always. As a last resolution you can always ( this is bad too ): Dim Const $Infinite = 999999;

TCPStartup()
TCPShutdown()

These two, I understand they are necessary; but give the programmer who is using the library the choice when to start up or when to shut down. Maybe he is using other TCP connections in his application and suddenly his socket is closed for no reason.

Proposed solution: Remove the startup and shutdown, and tell the programmer to do it him self! : )

AutoItSetOption("TCPTimeout", 2000)

Again this might conflict with what the rest of the script is doing. You can reset the original option when your transfer is finished. Look this up in help file.

Do
        $TCPAcc = TCPAccept($TCPListen)
        $TCPRecv = TCPRecv($TCPAcc, 9999999)
        $TCPDiff = TimerDiff($TCPTimerInt)
        If $TCPDiff >= $sTimeout Then
            $error = True
            ExitLoop
        EndIf
    Until $TCPRecv <> ""

This time out is unnecesary. If the connection stays open then the receiver should just be patient until the TCP connection closes by itself or the transfer is finished.

And last one:

If X Then Y
If Not X Then Z

You do this a lot, but it causes the expression to be evaluated twice! One time is enough, so do this instead:

If X Then
   Y
Else
   Z
EndIf

You are definitely on your way to writing a good and simple to use library! For a beginner user of AutoIt I am already impressed.

Link to comment
Share on other sites

Ok, I had a look at the library after your desperate plee. : )

But be warned, the code definitely needs some attention if you want other programmers to be able to use the library without modifying it.

$TCPSend = TCPSend($TCPConn, $oFileRead)
        If $TCPSend = 0 Then
            $error = True
        Else
            $buff = BinaryMid ($oFileOpen, $TCPSend + 1, BinaryLen ($oFileOpen) - $TCPSend)
            Do
                $TCPSend = TCPSend($TCPConn, $buff)
                $buff = BinaryMid ($buff, $TCPSend + 1, BinaryLen ($buff) - $TCPSend)
            Until $buff = ""
        EndIf

I'm not sure if I fully understand how this works, but it seems to me that you're trying to send the entire file in one piece ( regardless of size ) first and if that fails you are sending it in chunks; Why not send it in chunks immediately? The benefit of chunks is that the application will not hang and you can check for errors during the transfer. If an error occurs you should be able to reconnect and continue the file transfer on a new socket.

$TCPRecv = TCPRecv($TCPAcc, 9999999)
;------------------------------^

Why 9999999? Numbers like this that make no sense and should be avoided always. As a last resolution you can always ( this is bad too ): Dim Const $Infinite = 999999;

TCPStartup()
TCPShutdown()

These two, I understand they are necessary; but give the programmer who is using the library the choice when to start up or when to shut down. Maybe he is using other TCP connections in his application and suddenly his socket is closed for no reason.

Proposed solution: Remove the startup and shutdown, and tell the programmer to do it him self! : )

AutoItSetOption("TCPTimeout", 2000)

Again this might conflict with what the rest of the script is doing. You can reset the original option when your transfer is finished. Look this up in help file.

Do
        $TCPAcc = TCPAccept($TCPListen)
        $TCPRecv = TCPRecv($TCPAcc, 9999999)
        $TCPDiff = TimerDiff($TCPTimerInt)
        If $TCPDiff >= $sTimeout Then
            $error = True
            ExitLoop
        EndIf
    Until $TCPRecv <> ""

This time out is unnecesary. If the connection stays open then the receiver should just be patient until the TCP connection closes by itself or the transfer is finished.

And last one:

If X Then Y
If Not X Then Z

You do this a lot, but it causes the expression to be evaluated twice! One time is enough, so do this instead:

If X Then
   Y
Else
   Z
EndIf

You are definitely on your way to writing a good and simple to use library! For a beginner user of AutoIt I am already impressed.

Thanks for the indepth help! I will definatly take another look at the script and fix it up using all the suggestions you just gave me :)

Edited by DELmE
Link to comment
Share on other sites

Manadar:

I've just finished fixing up the areas that you pointed out to me but now when I transfer exe's they, for some reason, increase in size during transfer and no-longer work. I checked with my old version and found that the same thing happened when transfering larger files. This leads me to think that it has something with the way I am using the BinaryMid() function. Heres what I have:

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.0.0
 Author:         DELmE

 Script Function:
    _TCPFileRecv
    
Description:
    Receives a file being sent over a TCP connection
    
Parameters:
    rFile       The name of the file to save to
    Ip          The Ip to listen on for the file (default = @IPAddress1)
    Port        The port to listen on for incoming file data (default = 7894)
    
Return value:
    Success     _TCPFileRecv returns 1 if the file was successfully received and written
    Failure     _TCPFileRecv returns 0 if the function failed

#ce ----------------------------------------------------------------------------
Func _TCPFileRecv($rFile, $Ip = @IpAddress1, $Port = 7895)
    If $Ip = "" Then $Ip = @IpAddress1
    If $Ip = -1 Then $Ip = @IpAddress1
    If $Port = "" Then $Port = 7894
    If $Port = -1 Then $Port = 7894
    $opt = AutoItSetOption("TCPTimeout", 2000)
    Local $error = False
    Local $buff
    
    $TCPListen = TCPListen($Ip, $Port)
        
    $no_recv_count = 0
    
    $TCPAcc = TCPAccept($TCPListen)
    Do
        $TCPRecv = TCPRecv($TCPAcc, 100000)
        If $TCPRecv = "" Then
            $no_recv_count += 1
        Else
            $buff &= $TCPRecv
            $no_recv_count = 0
        EndIf
    Until $no_recv_count >= 15
    
    If $buff = "" Then
        $error = True
    Else
        $rFileOpen = FileOpen($rFile, 16 + 2)
        If $rFileOpen = -1 Then
            $error = True
        Else
            $rFileWrite = FileWrite($rFileOpen, $buff)
            If $rFileWrite = 0 Then
                $error = True
            EndIf
            FileClose($rFileOpen)
        EndIf
    EndIf
    TCPCloseSocket($TCPListen)
    AutoItSetOption("TCPTimeout", $opt)
    If $error = True Then
        Return 0
    Else
        Return 1
    EndIf
EndFunc ;==> _TCPFileRecv

#cs ----------------------------------------------------------------------------

 AutoIt Version: 3.3.0.0
 Author:         DELmE

 Script Function:
    _TCPFileSend

Description:
    Sends a file over a TCP connection

Parameters:
    sFile       The file to be sent
    Ip          The Ip to send on (default = @IPAddress1)
    Port        The port to send the file data on (default = 7894)

Return value:
    Success     _TCPFileSend returns 1 if the file was successfully sent out
    Failure     _TCPFileSend returns 0 if an error occurred

#ce ----------------------------------------------------------------------------
Func _TCPFileSend($sFile, $Ip = @IPAddress1, $Port = 7895)
    If $Ip = -1 Then $Ip = @IPAddress1
    If $Ip = "" Then $Ip = @IPAddress1
    If $Port = -1 Then $Port = 7894
    If $Port = "" Then $Port = 7894
    $opt = AutoItSetOption("TCPTimeout", 2000)
    Local $error = False
    $sFileOpen = FileOpen($sFile, 16 + 0)
    $sFileRead = FileRead($sFileOpen)
    FileClose($sFileOpen)
    $sFileSize = BinaryLen($sFileRead)
    
    $TCPConn = TCPConnect($Ip, $Port)
    If $TCPConn = -1 Then
        $error = True
    Else
        If $sFileSize < 100000 Then
            $TCPSend = TCPSend($TCPConn, $sFileRead)
            If $TCPSend = 0 Then
                $TCPConn = TCPConnect($Ip, $Port)
                $TCPSend = TCPSend($TCPConn, $sFileRead)
            EndIf
        Else
            $buff = $sFileRead
            Do
                $TCPSend = TCPSend($TCPConn, BinaryMid($buff, 1, 100000))
                If $TCPSend = 0 Then
                    $TCPConn = TCPConnect($Ip, $Port)
                    $TCPSend = TCPSend($TCPConn, BinaryMid($buff, 1, 100000))
                EndIf
                $buff = BinaryMid($buff, $TCPSend + 1)
            Until BinaryLen($buff) = 0
        EndIf
    EndIf
    TCPCloseSocket($TCPConn)
    AutoItSetOption("TCPTimeout", $opt)
    If $error = True Then
        Return 0
    Else
        Return 1
    EndIf
EndFunc ;==> _TCPFileSend

Any chance you (or anyone else who may be reading this) can point me in the right direction?

Thanks :)

Link to comment
Share on other sites

Hi!

I have a problem >_<

With big file (more than 19 mega) the script goes in "memory error" :(

Is there a solution?

thanks!

Hmm. I dunno what that is. Never happened to me. Do you have any other programs open that are using TCP or UDP?

Edit: I'm thinking that it may be because while the file is being sent the data is stored in a variable and maybe 19MB of data passes the length that AutoIt can carry in a variable, just taking a stab though as I don't really know..

Edited by DELmE
Link to comment
Share on other sites

  • 2 months later...
  • 7 months later...
  • 11 months later...

Hey guys,

I'm having some problems with the server:

I tried to transfer a file over the internet using my external IP and an open port.

What happens is that sometimes, everything works just perfectly, but often the server does not close the file handle after the transfer has finished.

You send a "close handle" request to the server with those two line breaks (line 147 I think). I tried using a different string for the request and replaced

If $rBuff = "WMpHUWr0FEZg" Then

with

If stringright($rBuff,12) = "WMpHUWr0FEZg" Then

which made it a little more reliable, but it still doesn't work every time.

Any ideas?

Edited by TheBrainiac
Link to comment
Share on other sites

  • 1 year later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...