WinBatch Tech Support Home

Database Search

If you can't find the information using the categories below, post a question over in our WinBatch Tech Support Forum.

TechHome

s... Socket Functions

Can't find the information you are looking for here? Then leave a message over on our WinBatch Tech Support Forum.

File Transfer Using sSendBinary and sRecvBinary

 Keywords:  sSendBinary sRecvLine sRecvBinary sSendLine Client Server Socket Listen Listener Remote Port Chunks Connect Connector File Transfer

Server - File transfer
;--------------------------------------------------------------------------------------
; FILE TRANSER - The SERVER LISTENER script
;
; Sets up a socket to listen for remote connects for multiple ports
; Prompts user for the Directory they want to transfer then sends all the
; Directories and Files in chunks to Client.
;--------------------------------------------------------------------------------------
;
; Keywords: sSendBinary sRecvLine Server Socket Listen Listener Remote Port Chunks File Transfer
;
; Issues Fixed:
; 2013.01.18
;    * Added Code Comments
;    * Freed the binary buffers created with BinaryAlloc uisng BinaryFree.
;    * Closed the open log file handle using FileClose.
;
; NOTES:
; Binary Buffer format
; OLD {Buffer handle}
; NEW {Buffer handle}
;
; This code uses an array to globally point to two file buffers. It interchangeably uses the
; two to store data or send data. It stores data in  one buffer ("old") until it is "filled",
; then fill the other ("new"). Once the "new" is filled, it pust the EOD of the "new" into
; the "old" so that the client computer is aware of the server's next buffer size approaching
; (this is INTEGRAL to using sRecvBinary, otherwise it hangs). After sending the "old", it then
; swaps the two using the labels (old and new) so that they can be reused. This is a bit of an
; advanced approach when it comes to educating  programmers and a better example may be developed
; for that purpose using what I've made.
;
; Developed by Trent Torkelson
; Modified by Deana Falk 2013.01.18
;--------------------------------------------------------------------------------------

AddExtender("WWHUG34I.DLL") ; HugeMath Extender
AddExtender("WWWSK44I.DLL") ; Winsock Extender

IntControl(5,1,0,0,0)  ; Controls whether system & hidden files or directories are seen and processed.
IntControl(39,0,0,0,0) ; Sets the file sharing mode for file reads. (prevent the file from being shared )

GoSub UDFs

BoxTitle("Total Sent: 0 Bytes To: No Client (Ctrl+Break to Quit)")

;--------------------------------------------------------------------------------------
; Allocate Two Large Binary Buffers and Store the Handles in an Array called bufarr_ptr
;--------------------------------------------------------------------------------------
PtrGlobalDefine(bufarr_ptr)
bufarr_ptr = ArrDimension(2,2)
bufarr_ptr[0,0] = "old"
bufarr_ptr[1,0] = "new"
bufarr_ptr[0,1] = BinaryAlloc(1000000)
bufarr_ptr[1,1] = BinaryAlloc(1000000)
BinaryEodSet(bufarr_ptr[0,1],0)
BinaryEodSet(bufarr_ptr[1,1],0)

;--------------------------------------------------------------------------------------
; Define an Error Log to Store Error Info
;--------------------------------------------------------------------------------------
PtrGlobalDefine(errorlogh_ptr)
errorlogh_ptr = FileOpen( DirScript():"\s_errorlog.txt","WRITE")

;--------------------------------------------------------------------------------------
; Define Port Numbers
;--------------------------------------------------------------------------------------
portlist = "20000":@TAB:"30000":@TAB:"40000":@TAB:"50000":@TAB:"60000"
portnum = AskItemlist("Choose Server/Listener Port",portlist, @TAB, @UNSORTED, @SINGLE, @TRUE )

;--------------------------------------------------------------------------------------
; Define Folder you would like to Transer to the Client
;--------------------------------------------------------------------------------------
thissourceroot = 'C:\TEMP\DATA\Access';AskDirectory("Select a folder to transfer: ","",Environment("SYSTEMDRIVE"),"",0)
If StrSub(thissourceroot,StrLen(thissourceroot),1)=="\" Then thissourceroot=StrSub(thissourceroot,1,StrLen(thissourceroot)-1)  ; Remove Trailing backslash

;--------------------------------------------------------------------------------------
; Define chunksize of the file to send
; Don't change unless you also modify the udfGetMaxBuffer() function chunksize to match
;--------------------------------------------------------------------------------------
chunksize = 250000

;--------------------------------------------------------------------------------------
; sOpen - Open a Listing Socket
;--------------------------------------------------------------------------------------
listensocket = sOpen()

;--------------------------------------------------------------------------------------
; Sets Up a Socket to Listen for Remote Connects on Multiple Ports
;--------------------------------------------------------------------------------------
listensocket = udfGetCon(listensocket,portnum)
If !IsNumber(listensocket)
   Message('Error','No Connection could be established: "':listensocket:'"')
   sClose(listensocket)
   Goto CleanUp
   Exit
EndIf

;--------------------------------------------------------------------------------------
; Define How Long to Wait for a Connection from a Client ( -1 Wait Forever)
;--------------------------------------------------------------------------------------
datasocket = udfWaitForCon(listensocket,-1)
If datasocket==0
   Message("Error",'No Connection could be established: "Destination connection timed out or local socket connection was terminated"')
   sClose(listensocket)
   Goto CleanUp
   Exit
EndIf

;--------------------------------------------------------------------------------------
; Initialize the Buffer Size in the Array as Zero
;--------------------------------------------------------------------------------------
udfSetBufferInfoSize(bufarr_ptr[udfGetBufferByType(bufarr_ptr,"old"),1],0)
udfSetBufferInfoSize(bufarr_ptr[udfGetBufferByType(bufarr_ptr,"new"),1],0)

; Start by recreating the . Checks if there is enough room in buffer for the Root directory
udfDirCreate(thissourceroot,bufarr_ptr[udfGetBufferByType(bufarr_ptr,"old"),1],chunksize,"r")

; Sets the EOD in the binary buffer
udfFixBufferSize(bufarr_ptr[udfGetBufferByType(bufarr_ptr,"old"),1],chunksize)

;Pass short name of the root directory to start cloning the Directory Tree
rslt = udfSrvCloneDirTree (thissourceroot,udfGet83Path(thissourceroot,"dir"),chunksize,@TRUE,0,datasocket,-1)

;--------------------------------------------------------------------------------------
; Clean up any Open Handles before exiting
;--------------------------------------------------------------------------------------
:CleanUp
sClose( listensocket )
BinaryFree( bufarr_ptr[0,1] )
BinaryFree( bufarr_ptr[1,1] )
FileClose( errorlogh_ptr )
Exit
;--------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------


;--------------------------------------------------------------------------------------
; UDFs
;--------------------------------------------------------------------------------------
:UDFs

#DefineFunction udfErrorHandler(errors)
   ;Error Handler - Currently does nothing.
   Return(1)
#EndFunction

#DefineFunction udfHuge_Compare(a,b)
   ; Compares two huge numbers and Return a value.
   ; 1 first parameter bigger than second parameter
   ; 0 parameters are the same
   ; -1 first parameter is smaller than the second parameter.
   c=huge_Subtract(a,b)
   If StrSub(c,1,1)=="-" Then x=-1
   If StrSub(c,1,1)!="-" && c=="0" Then x=0
   If StrSub(c,1,1)!="-" && c!="0" Then x=1
   Return x
#EndFunction

#DefineFunction udfHex2Uni(value)
   ; Converts a hex string to a Unicode string.
   IntControl(73,3,0,"udfErrorHandler",0)
   Return ChrHexToUnicode(value)
#EndFunction

#DefineFunction udfBinaryReadEx(filebuf,binoffset,fn,curoffset,chunksize)
   ; Reads a portion of a file into a binary buffer.
   IntControl(73,3,0,"udfErrorHandler",0)
   bytesread=BinaryReadEx(filebuf,binoffset,fn,curoffset,chunksize)
   If bytesread==0 Then bytesread="zerolength"
   Return bytesread
#EndFunction

;#DefineFunction udfBinaryWriteEx(filebuf,binoffset,nfn2,curoffset,chunksize)
;  Writes a portion of a binary buffer to a file.
;   IntControl(73,3,0,"udfErrorHandler",0)
;   byteswritten=BinaryWriteEx(filebuf,binoffset,nfn2,curoffset,chunksize)
;   If byteswritten==0 then byteswritten="zerolength"
;   Return byteswritten
;#EndFunction

#DefineFunction udfGetText(str)
   If ChrUnicodeToString(str)!=str Then str=ChrUnicodeToHex(str)
   Return str
#EndFunction

;#DefineFunction udfGetText2(str)
;   If StrTypeInfo(StrTypeInfo(str,0),-1)=="HexDg" && StrCmp(str,strupper(str))==0 && strlen(str)>3 then str=udfhex2Uni(str)
;   Return str
;#EndFunction

#DefineFunction udfGetMaxBuffer(filebuf,fsize,fileoffset,binoffset)
   ; Determine If user specified too Large of a chunkssize
   chunksize=250000
   midspaceleft=huge_Subtract(600000,binoffset)
   maxspaceleft=huge_Subtract(1000000,binoffset)
   ;Determine how much of the File is Left to Read
   fileleft=huge_Subtract(fsize,fileoffset)
   ;If the Remaining File is Greater than the Chunksize
   If udfHuge_Compare(fileleft,chunksize)==1
      ;If the Remaining File is Greater than the Maxspaceleft
      If udfHuge_Compare(fileleft,maxspaceleft)==1 Then chunksize=maxspaceleft
         Else chunksize=midspaceleft
   EndIf
   ;Returns updated Chunksize
   Return chunksize
#EndFunction

#DefineFunction udfGetCon(listensocket,portnum)
   ;Sets up a socket to listen for remote connects for multiple ports
   ctr=0
   gotcon=@FALSE
   errstr="Unknown Error"
   For i=1 To ItemCount(portnum,@TAB)
      sListen(listensocket,ItemExtract(i,portnum,@TAB))
      ;Pause( "PortNum",ItemExtract(i,portnum,@TAB));DEBUG
      datasocket=sAccept(listensocket,@FALSE)
      If datasocket == 0
         err=wxGetLastErr()
         If err!="12"
            errstr=wxGetErrDesc(err)
            ctr=ctr+1
         Else
            gotcon=@TRUE
         EndIf
      Else
         gotcon=@TRUE
      EndIf
      If gotcon==@TRUE Then Break
   Next
   If gotcon==@FALSE Then Return errstr
   Return listensocket
#EndFunction

#DefineFunction udfWaitForCon(listensocket,maxwait)
   ;Waits for a Client/Connecter to Connect
   curwait=-1
   nocon=@FALSE
   newcon=@FALSE
   datasocket=0
   While curwait<=maxwait && newcon==@FALSE
      datasocket=sAccept(listensocket,@FALSE)
      If datasocket == 0
         err=wxGetLastErr()
         If err=="12"
            If maxwait>-1 Then curwait=curwait+0.5
            TimeDelay(.5)
         Else
            nocon=@TRUE
         EndIf
      Else
         newcon=@TRUE
      EndIf
      If nocon==@TRUE Then Break
   EndWhile
   Return datasocket
#EndFunction

#DefineFunction udfGet83Path(path,type)
   ; Used to deal with Long file/directory names and 20+ length folder structures might exist.
   ; Compensates with checks on recursive functions to prevent nesting errors, as well as shorten
   ; path names to prevent fileopen and filecopy errors.
   IntControl(73,3,0,"udfErrorHandler",0)
   If StrSub(path,1,2)=="\\" Then mode="share"
      Else mode="local"
   file=ItemExtract(-1,path,"\")
   If type=="file" Then path=ItemRemove(-1,path,"\")
   If mode=="local"
      newpath=ItemExtract(1,path,"\")
      For i=2 To ItemCount(path,"\")-1
         newpath=FileNameShort(ItemInsert(ItemExtract(i,path,"\"),-1,newpath,"\"))
      Next
      If ItemCount(path,"\")>1 Then newpath=ItemInsert(ItemExtract(-1,path,"\"),-1,newpath,"\")
   Else
      newpath="\\":ItemExtract(3,path,"\"):"\":ItemExtract(4,path,"\")
      For i=5 To ItemCount(path,"\")-1
         newpath=FileNameShort(ItemInsert(ItemExtract(i,path,"\"),-1,newpath,"\"))
      Next
      If ItemCount(path,"\")>4 Then newpath=ItemInsert(ItemExtract(-1,path,"\"),-1,newpath,"\")
   EndIf
   If newpath==0 || newpath=="" Then Return path
   If type=="file" Then newpath=ItemInsert(file,-1,newpath,"\")
   Return newpath
#EndFunction

;#DefineFunction udfGetLongPath(path)
;   IntControl(73,3,0,"udfErrorHandler",0)
;   newpath=path
;   newpath=filenamelong(path)
;   If itemcount(newpath,"\")==itemcount(path,"\") && strlen(newpath)<250 then Return newpath
;      Else Return path
;#EndFunction

#DefineFunction udfAppendStr2List(str,arr)
   ;Accepts Directory Path and an Array
   ;Fills Array with Full Filepaths of All the Files Found
   If arr[0,0]==0 Then Return arr
   For i=1 To arr[0,0]
      arr[i,0]=str:arr[i,0]
   Next
   Return arr
#EndFunction

#DefineFunction udfSrvCloneDirTree (srcroot,srcroot83,chunksize,firstrun,cntr,datasocket,maxwait)
   ;Debug(1)
   cntr = cntr+1 ; Keep track of recurive calls
   If cntr>21 Then Return ; Avoid drilling to deep
   bufarr = PtrGlobal(bufarr_ptr) ; Get Access to Global Array Variable that Contains the Buffers
   topdirarr = DirInfoToArray(srcroot83:"\*.*",1) ; Return Directory Information, as an array.
   tempfilesarr = FileInfoToArray(srcroot83:"\*.*",1) ; Return File Information, as an array.
   ; Add the Directory to the Directory Array
   topdirarr = udfAppendStr2List(srcroot:"\",topdirarr)
   ; Add the Files to the File Array
   tempfilesarr = udfAppendStr2List(srcroot:"\",tempfilesarr)
   ; If No Directories and Files Found then Return False
   If topdirarr[0,0] == 0 && tempfilesarr[0,0] == 0 Then Return @FALSE
   ; Loop Thru all of the Directories
   For j=1 To topdirarr[0,0]
      dir=topdirarr[j,0] ;Get Directory
      ; Send CMD to Client to Create a Directory
      dircomplete=udfDirCreate(dir,*bufarr[udfGetBufferByType(*bufarr,"new"),1],chunksize,"s")
      While dircomplete==@FALSE
         udfSendBuffer(chunksize,0,datasocket,maxwait) ;test setup, to test valid structure of buffer chunk.
         dircomplete=udfDirCreate(dir,*bufarr[udfGetBufferByType(*bufarr,"new"),1],chunksize,"s")
      EndWhile
      ; Recurse
      udfSrvCloneDirTree (dir,udfGet83Path(dir,"dir"),chunksize,@FALSE,cntr,datasocket,maxwait)
   Next
   ;If There are Files to be Copied
   If tempfilesarr[0,0] != 0
      ; Loop Thru all of the Files
      For k=1 To tempfilesarr[0,0]
         curfile=tempfilesarr[k,0] ;Get File
         ; Send CMD to Client to Get a File
         filecomplete=udfCopyFile(curfile,udfGet83Path(curfile,"file"),*bufarr[udfGetBufferByType(*bufarr,"new"),1],chunksize,0)
         While filecomplete>-1
            udfSendBuffer(chunksize,0,datasocket,maxwait) ;test setup, to test valid structure of buffer chunk.
            filecomplete=udfCopyFile(curfile,udfGet83Path(curfile,"file"),*bufarr[udfGetBufferByType(*bufarr,"new"),1],chunksize,filecomplete)
         EndWhile
      Next
   EndIf
   ; Checks if functions first run, and if so cleaning out the buffers since the call is coming to an end, and no more objects are left to collect.
   ; EOD check on "new" buffer is to See if its clear and if so, make one call. The last sendbuffer call sends whats left of the "old" buffer"
   If firstrun==@TRUE
      If BinaryEodGet(*bufarr[udfGetBufferByType(*bufarr,"new"),1])>0 Then udfSendBuffer(chunksize,0,datasocket,maxwait)
      udfSendBuffer(chunksize,0,datasocket,maxwait)
   EndIf
   Return @TRUE
#EndFunction

#DefineFunction udfCopyFile(curfile,curfile83,filebuf,chunksize,fileoffset)
   errorlogh=PtrGlobal(errorlogh_ptr)
   newfileoffset=fileoffset
   openfile=@FALSE
   ;Check If the File Exists and is Not Read Deny
   If FileExist(curfile83)==2
      openfile=@TRUE
      FileWrite(*errorlogh,curfile:" - file is in read-deny mode.")
   EndIf
   ;If there was a problem Return -1
   If openfile==@TRUE Then Return -1
   ;Get the File Size of the File
   fsize=FileSize(curfile83,1)
   noroom=@FALSE
   ; Tell the Client Your Sending a File be sure to Include the FileSize
   ; so the Client Knows How Many Bytes to Read
   If fileoffset==0
      ; CMD Marker that includes Filename, FileSize and File Type to the End of the File
      finfo="CMD_!@{{":udfGetText(curfile):"|":fsize:"|":"f}}@!_CMD"
      infolen=StrByteCount(finfo,0)
      ; If Data is Less than the Chunksize Put in buffer
      If udfHuge_Compare(huge_Add(BinaryEodGet(filebuf),infolen),chunksize)==-1
         BinaryPokeStr(filebuf,BinaryEodGet(filebuf),finfo)
      Else
         noroom=@TRUE
      EndIf
   Else ; Only called If user specified too Large of a chunkssize
      chunksize=udfGetMaxBuffer(filebuf,fsize,fileoffset,BinaryEodGet(filebuf))
   EndIf
   If noroom==@TRUE Then Return newfileoffset
   filechunk=0
   ; Determine How Much Room there is in the Buffer
   spaceleft=huge_Subtract(chunksize,BinaryEodGet(filebuf))
   ; Determine How Much of the File is Left to Send
   fileleft=huge_Subtract(fsize,fileoffset)
   ; Determine New File Offset
   If udfHuge_Compare(fileleft,spaceleft)==1
      filechunk=spaceleft
      newfileoffset=huge_Add(newfileoffset,filechunk)
   Else
      filechunk=fileleft
      newfileoffset=-1
   EndIf
   ; Reads File into a Binary Buffer in Chunks until There is None Left
   While udfBinaryReadEx(filebuf,BinaryEodGet(filebuf),curfile83,fileoffset,filechunk)==0
      TimeDelay(.5)
   EndWhile
   ;Write to Log About Problems Rading the File
   If newfileoffset==-1
      If fsize!=FileSize(curfile83,1) Then FileWrite(*errorlogh,curfile:" - file could not be fully read.")
   EndIf
   Return newfileoffset
#EndFunction

#DefineFunction udfDirCreate(dir,filebuf,chunksize,type)
   ; r = root directory
   ; s = sub directory
   ; f = file
   dinfo="CMD_!@{{":udfGetText(dir):"|":type:"}}@!_CMD"
   infolen=StrByteCount(dinfo,0)
   noroom=@FALSE
   ; If there is room put the marker in the file buffer
   If udfHuge_Compare(huge_Add(BinaryEodGet(filebuf),infolen),chunksize)==-1
      BinaryPokeStr(filebuf,BinaryEodGet(filebuf),dinfo)
   Else
      noroom=@TRUE
   EndIf
   If noroom==@TRUE Then Return @FALSE
   Return @TRUE
#EndFunction

#DefineFunction udfSendBuffer(chunksize,cntr,datasocket,maxwait)
   ; Sends Data in the Buffer to the Client in Chunks
   bufarr=PtrGlobal(bufarr_ptr)
   rqst=""
   curwait=-1
   ; Determine Size of New Buffer
   totalsize=BinaryEodGet(*bufarr[udfGetBufferByType(*bufarr,"new"),1])
   If totalsize<=7 Then totalsize=0
   udfSetBufferInfoSize(*bufarr[udfGetBufferByType(*bufarr,"old"),1],totalsize)
   sentbytes=BinaryEodGet(*bufarr[udfGetBufferByType(*bufarr,"old"),1])
   ; Wait for CMD_GETDATA Request from Client
   rqst=sRecvLine(datasocket,100)
   While rqst!="!@CMD_GETDATA@!" && curwait<=maxwait
      TimeDelay(.5)
      If maxwait>-1 Then curwait=curwait+1
      rqst=sRecvLine(datasocket,100)
   EndWhile
   ; Sends binary data of the OLD Buffer to the Socket
   sSendBinary(datasocket,IntControl(42,*bufarr[udfGetBufferByType(*bufarr,"old"),1],0,0,0),sentbytes)
   ; Update Box Title with teh number of
   wincap=WinName() ; Adds sentbytes to the existing title of the box
   BoxTitle("Total Sent: ":huge_Add(sentbytes,StrSub(wincap,13,(StrIndex(wincap,"B",1,@FWDSCAN)-1)-13)):" Bytes To: ":wxGetInfo(2,datasocket):" (Ctrl+Break to Quit)")
   ; After sending the "old" Buffer, swap the two buffers using the labels (old and new) so that they can be reused.
   udfSwapBufferType()
   ;Set the New buffers End of Data to Zero
   BinaryEodSet(*bufarr[udfGetBufferByType(*bufarr,"new"),1],0)
   udfSetBufferInfoSize(*bufarr[udfGetBufferByType(*bufarr,"new"),1],0)
   Return
#EndFunction

;#DefineFunction udfDiskExistance(path)
;   IntControl(73,3,0,"udfErrorHandler",0)
;   Return DiskExist(path)
;#EndFunction
;
;#DefineFunction udfDirCreate2(path)
;  Create the Directory
;   IntControl(73,3,0,"udfErrorHandler",0)
;   dirtest=dirmake(path)
;;   IntControl(73,3,0,"generr",0)
;   If dirtest==@TRUE || udfDiskExistance(path)==@TRUE then Return @TRUE
;      Else Return @FALSE
;#EndFunction

#DefineFunction udfSetBufferInfoSize(filebuf,bufsize)
   ; Insert 7 bytes Indicating the File Size
   bufsize=StrFixBytes(bufsize,"?",7)
   BinaryPokeStr(filebuf,0,bufsize)
#EndFunction

#DefineFunction udfFixBufferSize(filebuf,bufsize)
   ; Updates a Buffers end of Data
   BinaryEodSet(filebuf,bufsize)
   Return
   spaceleft=huge_Subtract(bufsize,BinaryEodGet(filebuf))
   bufpad=StrFixBytes("","0",spaceleft)
   BinaryPokeStr(filebuf,BinaryEodGet(filebuf),bufpad)
   udfSetBufferInfoSize(filebuf,bufsize)
   Return
#EndFunction

#DefineFunction udfSwapBufferType()
   ;After sending the "old" Buffer, swap the two buffers using the labels (old and new) so that they can be reused.
   bufarr=PtrGlobal(bufarr_ptr)
   If *bufarr[0,0]=="new" Then *bufarr[0,0]="old"
      Else *bufarr[0,0]="new"
   If *bufarr[1,0]=="new" Then *bufarr[1,0]="old"
      Else *bufarr[1,0]="new"
   Return
#EndFunction

#DefineFunction udfGetBufferByType(bufarr,type)
   ; Determines the Buffer Type Old or New.
   If bufarr[0,0]==type Then Return 0
   If bufarr[1,0]==type Then Return 1
   Return
#EndFunction

Return


Client - Receive File Transer

;--------------------------------------------------------------------------------------
; FILE TRANSER - The CLIENT CONNECTOR script
;
; Sets up a socket to connect to a remote computer.
; Prompts the user for the Directory they want store transfered files to
; then reads all the transferred Directories and Files in chunks and
; stores them in the specified directory.
;--------------------------------------------------------------------------------------
;
; Keywords: sRecvBinary sSendLine Client Socket Connect Connector File Transfer
;
; Issues Fixed:
; 2013.01.18
;    * Added Code Comments
;    * Freed the binary buffers created with BinaryAlloc uisng BinaryFree.
;    * Closed the open log file handle using FileClose.
;    * Closed Open Socket.
;
; NOTES:
; sRecvBinary needs to know the actual filesize. The Server script sends this information
; using the start marker CMD_!@{{ and the end marker }}@!CMD
;
; Developed by Trent Torkelson
; Modified by Deana Falk 2013.01.18
;--------------------------------------------------------------------------------------

AddExtender("WWHUG34I.DLL") ; HugeMath Extender
AddExtender("WWWSK44I.DLL") ; Winsock Extender

IntControl(5,1,0,0,0)  ; Controls whether system & hidden files or directories are seen and processed.
IntControl(39,0,0,0,0) ; Sets the file sharing mode for file reads. (prevent the file from being shared )

GoSub UDFs

BoxTitle("Total Recv: 0 Bytes From: No Server")
BoxesUp("200,200,800,800",@NORMAL)

; Prompts for the Directory to Save the Files Transfered from the Server.
redir = 'C:\TEMP\DATAOUT'; AskDirectory("Select a folder to place files: ","",Environment("SYSTEMDRIVE"),"",0)
If StrSub(redir,StrLen(redir),1)=="\" Then redir=StrSub(redir,1,StrLen(redir)-1) ; Remove Trailing backslash

; Prompts For Host Name and Port Number to Connect to
serverhost = AskLine("Source Host",'Type the server in the format "NAMEORIPADDRESS:PORTNUMBER',"Localhost:20000")

;--------------------------------------------------------------------------------------
; sOpen - Open a Data Socket
;--------------------------------------------------------------------------------------
datasocket = sOpen()
ret=@FALSE
While ret!=@TRUE
   BoxTitle("Attempting Connection to ":ItemExtract(1,serverhost,":"):" on port ":ItemExtract(2,serverhost,":"):" (Ctrl+Break to Quit)")
   ; Connects to Server Socket
   ret=sConnect(datasocket,ItemExtract(1,serverhost,":"),ItemExtract(2,serverhost,":"))
   If ret==@FALSE Then TimeDelay(5)
EndWhile

;--------------------------------------------------------------------------------------
; Allocate Binary Buffer to Store the Data
;--------------------------------------------------------------------------------------
maxsize=250000
filebuf=BinaryAlloc(1000000)
BinaryEodSet(filebuf,0)
PtrGlobalDefine(errorlogh_ptr)

;--------------------------------------------------------------------------------------
; Define an Error Log to Store Error Info
;--------------------------------------------------------------------------------------
errorlogh_ptr=FileOpen(DirScript():"\c_errorlog.txt","WRITE")

;--------------------------------------------------------------------------------------
; Get Start Time
;--------------------------------------------------------------------------------------
stime = TimeYmdHms()


rslt = udfCliCloneDirTree(redir,udfGet83Path(redir,"dir"),filebuf,maxsize,datasocket,-1)

;--------------------------------------------------------------------------------------
; Get End Time
;--------------------------------------------------------------------------------------
etime = TimeYmdHms()

;--------------------------------------------------------------------------------------
; Display Results
;--------------------------------------------------------------------------------------
If rslt==@FALSE Then Message("Error","Directory transfer incomplete.")
Else Message("Success","Transfer Successful":@CRLF:"start time: ":stime:@CRLF:"end time: ":etime)

;--------------------------------------------------------------------------------------
; Clean up any Open Handles before exiting
;--------------------------------------------------------------------------------------
:CleanUp
sClose( datasocket )
BinaryFree( filebuf )
FileClose( errorlogh_ptr )
Exit
;--------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------
;--------------------------------------------------------------------------------------

;--------------------------------------------------------------------------------------
; UDFs
;--------------------------------------------------------------------------------------
:UDFs
#DefineFunction udfErrorHandler(errors)
   ; Error Handler - Currently does nothing.
   Return(1)
#EndFunction

#DefineFunction udfHuge_Compare(a,b)
   ; Compares two huge numbers and Return a value.
   ; 1 first parameter bigger than second parameter
   ; 0 parameters are the same
   ; -1 first parameter is smaller than the second parameter.
   c=huge_Subtract(a,b)
   If StrSub(c,1,1)=="-" Then x=-1
   If StrSub(c,1,1)!="-" && c=="0" Then x=0
   If StrSub(c,1,1)!="-" && c!="0" Then x=1
   Return x
#EndFunction

#DefineFunction udfHex2Uni(value)
   ; Converts a hex string to a Unicode string.
   IntControl(73,3,0,"udfErrorHandler",0)
   Return ChrHexToUnicode(value)
#EndFunction

;#DefineFunction udfGetText(str)
;   If ChrUnicodeToString(str)!=str then str=ChrUnicodeToHex(str)
;   Return str
;#EndFunction

#DefineFunction udfGetText2(str)
   If StrTypeInfo(StrTypeInfo(str,0),-1)=="HexDg" && StrCmp(str,StrUpper(str))==0 && StrLen(str)>3 Then str=udfHex2Uni(str)
   Return str
#EndFunction

#DefineFunction udfBinaryWriteEx(filebuf,binoffset,nfn2,curoffset,readsize)
   ; Writes a portion of a binary buffer to a file.
   IntControl(73,3,0,"udfErrorHandler",0)
   byteswritten=BinaryWriteEx(filebuf,binoffset,nfn2,curoffset,readsize)
   If byteswritten==0 Then byteswritten="zerolength"
   Return byteswritten
#EndFunction

;#DefineFunction udfGetMaxBuffer(filebuf,fsize,fileoffset,binoffset)
;   ; Determine If user specified too Large of a chunkssize
;   chunksize=250000
;   midspaceleft=huge_subtract(600000,binoffset)
;   maxspaceleft=huge_subtract(1000000,binoffset)
;   ;Determine how much of the File is Left to Read
;   fileleft=huge_subtract(fsize,fileoffset)
;   ;If the Remaining File is Greater than the Chunksize
;   If udfHuge_Compare(fileleft,chunksize)==1
;      ;If the Remaining File is Greater than the Maxspaceleft
;      If udfHuge_Compare(fileleft,maxspaceleft)==1 then chunksize=maxspaceleft
;         Else chunksize=midspaceleft
;   EndIf
;   ;Returns updated Chunksize
;   Return chunksize
;#EndFunction

#DefineFunction udfGet83Path(path,type)
   ; Used to deal with Long file/directory names and 20+ length folder structures might exist.
   ; Compensates with checks on recursive functions to prevent nesting errors, as well as shorten
   ; path names to prevent fileopen and filecopy errors.
   IntControl(73,3,0,"udfErrorHandler",0)
   If StrSub(path,1,2)=="\\" Then mode="share"
      Else mode="local"
   file=ItemExtract(-1,path,"\")
   If type=="file" Then path=ItemRemove(-1,path,"\")
   If mode=="local"
      newpath=ItemExtract(1,path,"\")
      For i=2 To ItemCount(path,"\")-1
         newpath=FileNameShort(ItemInsert(ItemExtract(i,path,"\"),-1,newpath,"\"))
      Next
      If ItemCount(path,"\")>1 Then newpath=ItemInsert(ItemExtract(-1,path,"\"),-1,newpath,"\")
   Else
      newpath="\\":ItemExtract(3,path,"\"):"\":ItemExtract(4,path,"\")
      For i=5 To ItemCount(path,"\")-1
         newpath=FileNameShort(ItemInsert(ItemExtract(i,path,"\"),-1,newpath,"\"))
      Next
      If ItemCount(path,"\")>4 Then newpath=ItemInsert(ItemExtract(-1,path,"\"),-1,newpath,"\")
   EndIf
   If newpath==0 || newpath=="" Then Return path
   If type=="file" Then newpath=ItemInsert(file,-1,newpath,"\")
   Return newpath
#EndFunction

;#DefineFunction udfGetLongPath(path)
;   IntControl(73,3,0,"udfErrorHandler",0)
;   newpath=path
;   newpath=filenamelong(path)
;   If itemcount(newpath,"\")==itemcount(path,"\") && strlen(newpath)<250 then Return newpath
;      Else Return path
;#EndFunction

;#DefineFunction udfAppendStr2List(str,arr)
;   ;Accepts Directory Path and an Array
;   ;Fills Array with Full Filepaths of All the Files Found
;   If arr[0,0]==0 then Return arr
;   For i=1 to arr[0,0]
;      arr[i,0]=str:arr[i,0]
;   Next
;   Return arr
;#EndFunction

#DefineFunction udfDiskExistance(path)
   IntControl(73,3,0,"udfErrorHandler",0)
   Return DiskExist(path)
#EndFunction

#DefineFunction udfDirCreate2(path)
   ; Create the Directory
   IntControl(73,3,0,"udfErrorHandler",0)
   dirtest=DirMake(path)
;   IntControl(73,3,0,"generr",0)
   If dirtest==@TRUE || udfDiskExistance(path)==@TRUE Then Return @TRUE
      Else Return @FALSE
#EndFunction

#DefineFunction udfGetBuffer(filebuf,maxsize,redir,cntr)
   ;Retrieve the Contents of the Buffer
   cntr=cntr+1
   If cntr>21 Then Return
   errorlogh=PtrGlobal(errorlogh_ptr)
   ptr_bufdata=PtrPersistent(bufdata,"")
   ptr_fileoffset=PtrPersistent(fileoffset,0)
   ptr_binoffset=PtrPersistent(binoffset,7)
   ptr_srcroot=PtrPersistent(srcroot,"")
   data=@TRUE
   If *ptr_bufdata==""
      ; Look for CMD marker
      structure=BinaryTagInit(filebuf,"CMD_!@{{","}}@!_CMD")
      structure=BinaryTagFind(structure)
      If structure!=""
         *ptr_bufdata=BinaryTagExtr(structure,0)
         infolength=BinaryTagLen(structure,1)
         *ptr_binoffset=huge_Add(*ptr_binoffset,infolength)
         BinaryTagRepl(structure,StrFill("0",infolength))
      Else
         data=@FALSE
         *ptr_fileoffset=0
         *ptr_binoffset=7
         BinaryEodSet(filebuf,0)
      EndIf
   EndIf
   If data==@FALSE Then Return
   objtype=ItemExtract(-1,*ptr_bufdata,"|")
   ;--------------------------------------------------------------------------------------
   ; Subdirectory
   ;--------------------------------------------------------------------------------------
   If objtype=="s"  ;Subdirectory
      dirname=udfGetText2(ItemExtract(1,*ptr_bufdata,"|"))
      dirname=StrReplace(dirname,*ptr_srcroot,redir)
      dirname=udfGet83Path(dirname,"dir")
      udfDirCreate2(dirname)
      *ptr_bufdata=""
      *ptr_fileoffset=0
   ;--------------------------------------------------------------------------------------
   ; File
   ;--------------------------------------------------------------------------------------
   ElseIf objtype=="f" ;File
      filename=udfGetText2(ItemExtract(1,*ptr_bufdata,"|"))
      file_size=ItemExtract(2,*ptr_bufdata,"|")
      If filename=="" || file_size==""
         Message("Error","Invalid File Information Found.")
         Exit
      EndIf
      filename=StrReplace(filename,*ptr_srcroot,redir)
      filename=udfGet83Path(filename,"file")
      spaceleft=huge_Subtract(maxsize,*ptr_binoffset)
      fileleft=huge_Subtract(file_size,*ptr_fileoffset)
      If udfHuge_Compare(fileleft,spaceleft)==1 Then filechunk=spaceleft
         Else filechunk=fileleft
      While udfBinaryWriteEx(filebuf,*ptr_binoffset,filename,*ptr_fileoffset,filechunk)==0
         TimeDelay(.5)
      EndWhile
      *ptr_binoffset=huge_Add(*ptr_binoffset,filechunk)
      *ptr_fileoffset=huge_Add(*ptr_fileoffset,filechunk)
      If *ptr_fileoffset==file_size
         If file_size!=FileSize(filename,1) Then FileWrite(*errorlogh,filename:" - file could not be fully written.")
         *ptr_fileoffset=0
         *ptr_bufdata=""
      EndIf
   Else
      ;--------------------------------------------------------------------------------------
      ; Directory Root
      ;--------------------------------------------------------------------------------------
      If objtype=="r" ;Directory Root
         *ptr_srcroot=udfGetText2(ItemExtract(1,*ptr_bufdata,"|"))
         *ptr_bufdata=""
         *ptr_fileoffset=0
      EndIf
   EndIf
   If *ptr_binoffset==maxsize
      BinaryEodSet(filebuf,0)
      *ptr_binoffset=7
      data=@FALSE
   EndIf
   If data==@FALSE Then Return
   udfGetBuffer(filebuf,maxsize,redir,cntr)
   Return
#EndFunction

#DefineFunction udfCliCloneDirTree(redir,redir83,filebuf,maxsize,datasocket,maxwait)
   recvbytes=0
   dataleft=@TRUE
   ; Loop Until All Data is Recieved
   While maxsize>0
      ret=@FALSE
      curwait=-1
      ; Send Request to Server to Start File Transer
      ret=sSendLine(datasocket,"!@CMD_GETDATA@!")
      While ret==@FALSE && curwait<=maxwait
         TimeDelay(.5)
         If maxwait>-1 Then curwait=curwait+1
         ret=sSendLine(datasocket,"!@CMD_GETDATA@!")
      EndWhile
      If ret==@FALSE Then Break
      BinaryEodSet(filebuf,maxsize)
      ; Gets binary data from a socket
      recv=sRecvBinary(datasocket,IntControl(42,filebuf,0,0,0),maxsize)
      If recv==0 Then Continue
      ; Update Box Title with the Total Number of Bytes Recieved
      recvbytes=huge_Add(recvbytes,recv)
      BoxTitle("Total Recv: ":recvbytes:" Bytes From: ":wxGetInfo(2,datasocket):" (Ctrl+Break to Quit)")
      ; Read Data Until There is No More
      nextsize=StrReplace(BinaryPeekStr(filebuf,0,7),"?","")
      While BinaryEodGet(filebuf)>0
         udfGetBuffer(filebuf,maxsize,redir,0)
      EndWhile
      maxsize=nextsize
   EndWhile
   If ret==@FALSE || recv==0 Then Return @FALSE
   Return @TRUE
#EndFunction

Return


Article ID:   W17626
Filename:   File Transfer Using sSendBinary and sRecvBinary.txt
File Created: 2013:01:18:12:57:04
Last Updated: 2013:01:18:12:57:04