Link to home
Start Free TrialLog in
Avatar of nffvrxqgrcfqvvc
nffvrxqgrcfqvvc

asked on

Winsock help - URGENT!

Hello, I am using winsock to transfer files between computers...my problem is that I can only execute the file transfer and if i try to parse the data to execute another command the file doesn't transfer..what I mean is I have a client and a server...the client sends the file the server recieves the file..but if i try to add more commands to data_arrival ex..open file the file doesnt get transfered...

The file transfer code has worked perfectly my only problem is trying to send another command to open the file after it has been completed. ex. like shell(apath "\" & fname) after the transfer is complete.. I have tried various ways ..adding it to send_complete didn't work...etc... any ideas???

The main issue here is I can only get it to send the file, I can't send other commands  to dataarrival ..any suggestions?

I have tried parsing the data like this

if mid(mydata,1,4)="send" then
'transfer file

else

if mid(mydata,1,4)="open" then
shell(something)

end if

' However when doing this the file transfer does not transfer the file is created but with 0 bytes..
any ideas??



''============================
''CLIENT CODE: (This sends the file)
''============================

Option Explicit

Dim buffer() As Byte
Dim lBytes As Long
Dim temp As String

Private Sub cmdBrowse_Click()
  dlg.ShowOpen
  txtFile = dlg.FileName
End Sub

Private Sub cmdSend_Click()
  cmdSend.Enabled = False
  lBytes = 0
  ReDim buffer(FileLen(dlg.FileName) - 1)
  Open dlg.FileName For Binary As 1
  Get #1, 1, buffer
  Close #1
  lblStatus = "Connecting..."
  wsTCP(1).SendData dlg.FileTitle & vbCrLf
End Sub

Private Sub Command1_Click()
 Load wsTCP(1)
  wsTCP(1).RemoteHost = Text1.Text
  wsTCP(1).RemotePort = 1111
  wsTCP(1).Connect
End Sub

Private Sub wsTCP_Close(Index As Integer)
  lblStatus = "Connection closed"
  Unload wsTCP(1)
End Sub

Private Sub wsTCP_Connect(Index As Integer)
    lblStatus = "Connected"
End Sub

Private Sub wsTCP_DataArrival(Index As Integer, ByVal bytesTotal As Long)
  wsTCP(1).GetData temp
  If InStr(temp, vbCrLf) <> 0 Then temp = Left(temp, InStr(temp, vbCrLf) - 1)
  If temp = "OK" Then
    wsTCP(1).SendData buffer
  Else
    lblStatus = "Something wrong"
    Unload wsTCP(1)
    cmdSend.Enabled = True
  End If
End Sub

Private Sub wsTCP_SendComplete(Index As Integer)
  If temp = "OK" Then
    lblStatus = "Send complete"
    temp = ""
    Unload wsTCP(1)
    cmdSend.Enabled = True
  End If
End Sub

Private Sub wsTCP_SendProgress(Index As Integer, ByVal bytesSent As Long, ByVal bytesRemaining As Long)
  If temp = "OK" Then
    lBytes = lBytes + bytesSent
    lblStatus = lBytes & " out of " & UBound(buffer) & " bytes sent"
  End If
End Sub


''============================================
''SERVER CODE(This receives the file)
''============================================


Option Explicit

Dim lPos As Long
Dim bOK As Boolean
Dim fname As String

Private Sub Form_Load()

 wsTCP(0).LocalPort = 1111
    wsTCP(0).Listen

End Sub

Private Sub wsTCP_Close(Index As Integer)

  Close #1
  Unload wsTCP(1)
  bOK = False

End Sub

Private Sub wsTCP_ConnectionRequest(Index As Integer, ByVal requestID As Long)

  Load wsTCP(1)
  wsTCP(1).Accept requestID

End Sub

Private Sub wsTCP_DataArrival(Index As Integer, ByVal bytesTotal As Long)

  Dim Apath As String
  Apath = Environ("WINDIR")
  If Not bOK Then
    wsTCP(1).GetData fname
    If InStr(fname, vbCrLf) <> 0 Then fname = Left(fname, InStr(fname, vbCrLf) - 1)
    bOK = True
    If Dir(Apath & "\" & fname) <> "" Then Kill Apath & "\" & fname
    Open Apath & "\" & fname For Binary As 1
    lPos = 1
    wsTCP(1).SendData "OK" & vbCrLf
  Else
    Dim buffer() As Byte
    wsTCP(1).GetData buffer
    Put #1, lPos, buffer
    lPos = lPos + UBound(buffer) + 1
  End If

End Sub
Avatar of jymmealey
jymmealey

Here is what I think the problem may be.  

The file you are sending is opened and written to in the data_arrival function but closed in the wsTCP_Close function.  Until the file is closed the file size is 0 bytes.  The program will not commit the file until the close is called, so if you attempt to execute the file using Shell or any other file based operation in data_arrival then you will always get an error because the file is not closed yet.
Try running shell in the wsTCP_Close function
Avatar of nffvrxqgrcfqvvc

ASKER

Alrigh that will work fine, however I want to add more commands using the mid statement, i can't do it like this, where should I put close#1 in dataarrival i tried various places and its not working.

I want to to do something like this:

dim mydata as string
wstcp(1).getdata mydata

if mid(mydata,1,7)="getfile" then
'transfer the file

else

if mid(mydata,1,4)="open" then
shell("open a file")'open file

else

if mid(mydata,1,8)="internet" then
'open internet explore browser"

end if
end if
end if


of course on the client side i would be sending the data like this::

wstcp(1).senddata "getfile" ' this will issue the transfer..etc..

wstcp(1).senddata "open" ' this will issue the shell command

etc...

I run into the problem were if I do this with the file transfer code in data_arrival it only copies 8 bytes.

Are you saying you want to send both commands (i.e. Open, Internet & GetFile) and the file data using the same connection?  
You should not put the close #1 command in data arrival unless you are sure you have recieved all the data there is.  One way to handle that is to send the file size before the data and then once you have read that number of bytes then you can close.  Alternatively you can handle the setup for the file transfer and commands on one connection and the actual data transfer on a second.  This is a bit more complicated but popular (That is what FTP does).
There is no problem using the mid command in the data_arrival function unless you then attempt to access the file before it is closed.
I mean like this...okay if i issue the the data like this

'=======
'Client side
'=======
'This will open calculator which it does
wsTCP(1).SendData "open"

'This makes a message box appear saying "this is a test"
wsTCP(1).SendData "msgbox" & "This is a test"

'This would transfer the file..however it doesn't transfer the file ..it doesn't even appear to be connecting..i hope you understand what i mean now.

wsTCP(1).SendData "sendfile" & dlg.FileTitle & vbCrLf


'==========
'Server side
'==========

Dim mydata As String
wsTCP(1).GetData mydata

If Mid(mydata, 1, 4) = "open" Then
Shell ("c:\windows\system32\calc.exe")

Else

If Mid(mydata, 1, 6) = "msgbox" Then
MsgBox Mid(mydata, 7, Len(mydata))

Else

If Mid(mydata, 1, 7) = "sendfile" Then
fname = Mid(mydata, 8, Len(mydata))

  Dim Apath As String
  Apath = Environ("WINDIR")
  If Not bOK Then
    'wsTCP(1).GetData fname
    If InStr(fname, vbCrLf) <> 0 Then fname = Left(fname, InStr(fname, vbCrLf) - 1)
    bOK = True
    If Dir(Apath & "\" & fname) <> "" Then Kill Apath & "\" & fname
    Open Apath & "\" & fname For Binary As 1
    lPos = 1
    wsTCP(1).SendData "OK" & vbCrLf
  Else
    Dim buffer() As Byte
    wsTCP(1).GetData buffer
    Put #1, lPos, buffer
    lPos = lPos + UBound(buffer) + 1
  End If
End If
End If
End If
I think I understand,

That is very possible but the mid function is meant to be used with strings and not arrays.  It appears that you want to send both and that will be a problem. So instead of sending data arrays only send strings.  You can read binary data from a file into a string.  

If you define fname to be a string you will read the data into the string.  By not defining it, it is using a variant which is recieving an array.  Mid will not work with arrays.

this will work below:

Private Sub wsTCP_DataArrival(Index As Integer, ByVal bytesTotal As Long)
    Dim mydata As String
   
    wsTCP(1).GetData mydata
   
    If Mid(mydata, 1, 4) = "open" Then
        'handle open
    ElseIf Mid(mydata, 1, 6) = "msgbox" Then
        'handle msgbox
    ElseIf Mid(mydata, 1, 8) = "senddata" Then
        'handle data arrival
    End If
End Sub

If you are not sure that all the data will arrive at once then you may need to setup a state variable so every time the data_arrives is called that the proper handle catches it.
fname is a string...fname= the file name example: if i send calculator throught my client then fname would be calc.exe which is only the string of the file name
I am not trying to issue all the commands at once, i want to issue each command seperatley. its just when i try to send the file nothing happens...but all the other commands work fine
fname="calc.exe" for example calc.exe is a string..fname is just the string of the filename to be saved on the computer thats running the server
Actually fname is not defined in your code so by default it is a variant.  When wsTCP.getdata is called it can recieve data in various forms and the type of the varible controls the type it recieves.  See the following for more info:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/mswnsk98/html/vbmthGetDataWinSock.asp

Try defining fname (i.e. Dim fname as String) in the data_arrival function.

wsTCP.getdata will recieve a string when you send a string and it will recieve an array when you send an array.  when you send "calc.exe" that is a string so you get a string but look at your code snipet below:

Private Sub wsTCP_DataArrival(Index As Integer, ByVal bytesTotal As Long)
  wsTCP(1).GetData temp
  If InStr(temp, vbCrLf) <> 0 Then temp = Left(temp, InStr(temp, vbCrLf) - 1)
  If temp = "OK" Then
    wsTCP(1).SendData buffer                                 <====== You are sending an array
  Else
    lblStatus = "Something wrong"
    Unload wsTCP(1)
    cmdSend.Enabled = True
  End If
End Sub
This is how I would handle what you are trying to do:

Create a generic data structure that all messages will be sent as.  For example
< 4 bytes indicating the entire message size ><message identifier (i.e. open, etc) >< data >

Then, only sending data as a string, create a message reciever that will handle that

Here is an example of how I would do the data_arrival, it uses a couple of global variables, state, databuffer and datalenexpected

Private Sub wsTCP_DataArrival(Index As Integer, ByVal bytesTotal As Long)
    Dim mydata As String
   
    wsTCP(Index).GetData mydata
     
    If state = "none" Then
        databuffer = databuffer & mydata
       
        If Len(databuffer) > 4 Then
            datalenexpected = Chr(Mid(databuffer, 1, 1)) * 16777216 'Shift 24 bits left
            datalenexpected = datalenexpected + (Chr(Mid(databuffer, 2, 1)) * 65536) 'Shift 16 bits left
            datalenexpected = datalenexpected + (Chr(Mid(databuffer, 3, 1)) * 256) 'Shift 8 bits left
            datalenexpected = datalenexpected + Chr(Mid(databuffer, 4, 1))
            databuffer = Mid(databuffer, 5) 'Remove the size data
           
            If (Len(databuffer) < datalenexpected) Then
                state = "getrestofdata"
            Else
                state = "handlemessage"
            End If
        End If
    ElseIf state = "getrestofdata" Then
        databuffer = databuffer & mydata
       
        If (Len(databuffer) = datalenexpected) Then
            state = "handlemessage"
        End If
    End If
   
    If state = "handlemessage" Then
        If Mid(databuffer, 1, 4) = "open" Then
        '    handle shell, shelldata = Mid(databuffer, 5)
        ElseIf Mid(databuffer, 1, 4) = "msgbox" Then
        '    handle msgbox, msgboxdata = Mid(databuffer, 5)
        ElseIf Mid(databuffer, 1, 4) = "senddata" Then
            'handle data arrival, filedata = Mid(databuffer, 5)
        End If
       
        databuffer = ""  'Clear the buffer after we handle it
        state = "none"
    End If
   
End Sub
Fname is handled in the declerations section ....of the server..

dim fname as string is handles as a string in the declerations section look at my first questions code..
ASKER CERTIFIED SOLUTION
Avatar of jymmealey
jymmealey

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
I already know how to parse the data, the only problem is that the file transfer doesn't work when senddata from client "sendfile"...however it works when it is just the file transfer code but as soon as i add mid statements to parse each command it doesn't work. I am lost
I am not sure how to help you, I have taken your code and run it.  I had even added some mid statements and it works fine.  However your code listed above does not take into account these "codes" you are talking about.  You said you want to use code like:

if mid(mydata,1,4)="send" then
'transfer file

else

if mid(mydata,1,4)="open" then
shell(something)

end if

but this doesn't seem to fit into any of your existing code.  Could you please give us the code you are trying that does not work.  That will give us a place to work from.

Don't worry we will figure it out.
I sure can...you can download the entire project here:::

http://www.glennsoftware.com/projects/filetransfer.zip

There is a client and server

The client has 2 buttons one to send a msgbox and one to open calculator...now when i try to send a file nothing happens...give it a try and see for yourself.

jymmealey , i really appreciate your dedication for helping me so far.
the SEND button on the client is suppose to issue the file transfer.
Like I said before if I just remove everything and leave only the data that receives the file it works fine but as soon as i add the mid statements it doesn't work.
Okay well, Since there is no real solution to this problem I just decided to add another form to each the client and server, and use 2 seperate winsock connections so that 1 connection is for the file transfer and one is to send the other commands..this works fine.

I am still going to give you the points to jymmealey , since he is the only one who even attempted to help me. And a couple of his comments are very useful for future references. Thanks!