async socket server problem on windows 2000

E

Engineerik

I have created a socket server and a client which both run on the same
computer. The socket connection is done over localhost port 11050.
The server and the client are based on the sample asynchronous socket server
example code from the msdn library included with visual studio 2005.

The code works fine when run on windows xp.
If the applications are run on a windows 2000 computer there seems to be a
problem passing stings over 1440 characters in length.

When a return string (len>1440) is sent from the server to the client, only
the first 1440 characters actually travel to the client. I have used a
tcpspy program to confirm that the 1440 characters recieved at the client are
indeed all that left the server.

When I pass new input from the client to the server the server sends more
data back to the client but what arrives at the client is the remainder of
the string from the previous call.

From that point on all the communication between the client and server are
out of sync.

Sometimes a subsequent send from the server to the client will end up
pushing both the previous result and the current output so that the server
"catches up" to the client but this behavior is unpredictable.

Whenever the client and server are "caught up" with each other, s string
passed from the server to the client with a length greater than 1440 will
result in only the first 1440 characters being sent back and the client and
server are out of sync again.

Anyone know why this would happen on win2k?
 
T

Tom Shelton

I have created a socket server and a client which both run on the same
computer. The socket connection is done over localhost port 11050.
The server and the client are based on the sample asynchronous socket server
example code from the msdn library included with visual studio 2005.

The code works fine when run on windows xp.
If the applications are run on a windows 2000 computer there seems to be a
problem passing stings over 1440 characters in length.

When a return string (len>1440) is sent from the server to the client, only
the first 1440 characters actually travel to the client. I have used a
tcpspy program to confirm that the 1440 characters recieved at the client are
indeed all that left the server.

When I pass new input from the client to the server the server sends more
data back to the client but what arrives at the client is the remainder of
the string from the previous call.

From that point on all the communication between the client and server are
out of sync.

Sometimes a subsequent send from the server to the client will end up
pushing both the previous result and the current output so that the server
"catches up" to the client but this behavior is unpredictable.

Whenever the client and server are "caught up" with each other, s string
passed from the server to the client with a length greater than 1440 will
result in only the first 1440 characters being sent back and the client and
server are out of sync again.

Anyone know why this would happen on win2k?

With TCP/IP you are not guarenteed to get all of the data from a single
send in asigle receive. Generally, with string based protocols, a
predetermined end-of-transmission character is chosed (often CR/LF) to
signal with all data is received. If the data read doesn't end with the
end-of-transmission, then the code must read the socket again.
 
E

Engineerik

Tom Shelton said:
With TCP/IP you are not guarenteed to get all of the data from a single
send in asigle receive. Generally, with string based protocols, a
predetermined end-of-transmission character is chosed (often CR/LF) to
signal with all data is received. If the data read doesn't end with the
end-of-transmission, then the code must read the socket again.

Tom,

I loop until I read all available data. The problem is that when the return
string is longer than 1440 characters, only the first 1440 get passed back.
See code below. When I tried looping until I get the end of file marker I
only end up blocking indefinitely and nothing happens.

I also tried calling the recieve sub multiple times if the string recieved
does not end with the "<EOF>" marker. In that case the program blocks
indefinitely on the second call to recieve because the send did not transmit
the entire string. The second call just blocks because there are no bytes
available to be received.

As I said before, I used a tcpspy program to watch what was being sent over
the socket and only the first 1440 characters get sent from the server. The
remainder of the string Never gets sent until a second send is done from the
server.


Private Shared Sub Receive()
Dim bytesReceived(255) As [Byte]
Dim bytes As Int32
Dim sLine As String = String.Empty

Try
' The following will block until the page is transmitted.
Do
bytes = pClient.Receive(bytesReceived, bytesReceived.Length, 0)
sLine = sLine & Encoding.ASCII.GetString(bytesReceived, 0, bytes)
Loop While pClient.Available > 0
'The following loop just block indefinitely
'Loop While not sLine.EndsWith("<EOF>")
ErrorCode = 0
Catch ex As SocketException
ErrorCode = 89
response = "SocketException " & ex.SocketErrorCode.ToString & _
" during receive attempt."


Catch ex As Exception
ErrorCode = 88
response = ex.Source & ":" & ex.Message
'Note: The control which displays the error message must
' handle any format issues like no CRLF or max length.
End Try

If bAbort Then
ErrorCode = 88
response = "Send/Receive cancelled by user."
Else
If pClient.Connected Then
response = sLine
Else
Console.WriteLine("Receive failed due to {0}", response)
End If
End If

End Sub 'Receive


Thanks for the suggestion,
Erik Warren
 
T

Tom Shelton

Tom Shelton said:
With TCP/IP you are not guarenteed to get all of the data from a single
send in asigle receive. Generally, with string based protocols, a
predetermined end-of-transmission character is chosed (often CR/LF) to
signal with all data is received. If the data read doesn't end with the
end-of-transmission, then the code must read the socket again.

Tom,

I loop until I read all available data. The problem is that when the return
string is longer than 1440 characters, only the first 1440 get passed back.
See code below. When I tried looping until I get the end of file marker I
only end up blocking indefinitely and nothing happens.

I also tried calling the recieve sub multiple times if the string recieved
does not end with the "<EOF>" marker. In that case the program blocks
indefinitely on the second call to recieve because the send did not transmit
the entire string. The second call just blocks because there are no bytes
available to be received.

As I said before, I used a tcpspy program to watch what was being sent over
the socket and only the first 1440 characters get sent from the server. The
remainder of the string Never gets sent until a second send is done from the
server.


Private Shared Sub Receive()
Dim bytesReceived(255) As [Byte]
Dim bytes As Int32
Dim sLine As String = String.Empty

Try
' The following will block until the page is transmitted.
Do
bytes = pClient.Receive(bytesReceived, bytesReceived.Length, 0)
sLine = sLine & Encoding.ASCII.GetString(bytesReceived, 0, bytes)
Loop While pClient.Available > 0
'The following loop just block indefinitely
'Loop While not sLine.EndsWith("<EOF>")
ErrorCode = 0
Catch ex As SocketException
ErrorCode = 89
response = "SocketException " & ex.SocketErrorCode.ToString & _
" during receive attempt."


Catch ex As Exception
ErrorCode = 88
response = ex.Source & ":" & ex.Message
'Note: The control which displays the error message must
' handle any format issues like no CRLF or max length.
End Try

If bAbort Then
ErrorCode = 88
response = "Send/Receive cancelled by user."
Else
If pClient.Connected Then
response = sLine
Else
Console.WriteLine("Receive failed due to {0}", response)
End If
End If

End Sub 'Receive


Thanks for the suggestion,
Erik Warren

Erik...

Can you post the code where the data is actually being sent. This looks
like an issue with buffering.
 
E

Engineerik

Tom Shelton said:
Erik...

Can you post the code where the data is actually being sent. This looks
like an issue with buffering.

Tom,

Thanks for looking into this!
Below is the asynchronous send code from my server app.
--------

Private Shared Sub Send(ByVal handler As Socket, ByVal data As String)
' Convert the string data to byte data using ASCII encoding.
Dim byteData As Byte() = Encoding.ASCII.GetBytes(data)

' Begin sending the data to the remote device.
handler.BeginSend(byteData, 0, byteData.Length, 0, New
AsyncCallback(AddressOf SendCallback), handler)
End Sub 'Send


Private Shared Sub SendCallback(ByVal ar As IAsyncResult)
' Retrieve the socket from the state object.
Dim handler As Socket = CType(ar.AsyncState, Socket)

' Complete sending the data to the remote device.
Dim bytesSent As Integer = handler.EndSend(ar)
Console.WriteLine("Sent {0} bytes to client.", bytesSent)

' Create the state object for the async receive.
Dim state As New StateObject
state.workSocket = handler
handler.BeginReceive(state.buffer, 0, StateObject.BufferSize, 0, New
AsyncCallback(AddressOf ReadCallback), state)


End Sub 'SendCallback

------

After the handler.endsend the console.writeline always shows the full length
that was sent even though the client only recieves the first 1440 characters.

Thanks for your help.
Erik Warren
 
T

Tom Shelton

Engineerik said:
Tom Shelton said:
With TCP/IP you are not guarenteed to get all of the data from a single
send in asigle receive. Generally, with string based protocols, a
predetermined end-of-transmission character is chosed (often CR/LF) to
signal with all data is received. If the data read doesn't end with the
end-of-transmission, then the code must read the socket again.

Tom,

I loop until I read all available data. The problem is that when the
return
string is longer than 1440 characters, only the first 1440 get passed
back.
See code below. When I tried looping until I get the end of file marker I
only end up blocking indefinitely and nothing happens.

I also tried calling the recieve sub multiple times if the string recieved
does not end with the "<EOF>" marker. In that case the program blocks
indefinitely on the second call to recieve because the send did not
transmit
the entire string. The second call just blocks because there are no bytes
available to be received.

As I said before, I used a tcpspy program to watch what was being sent
over
the socket and only the first 1440 characters get sent from the server.
The
remainder of the string Never gets sent until a second send is done from
the
server.


Private Shared Sub Receive()
Dim bytesReceived(255) As [Byte]
Dim bytes As Int32
Dim sLine As String = String.Empty

Try
' The following will block until the page is transmitted.
Do
bytes = pClient.Receive(bytesReceived, bytesReceived.Length,
0)
sLine = sLine & Encoding.ASCII.GetString(bytesReceived, 0,
bytes)
Loop While pClient.Available > 0
'The following loop just block indefinitely
'Loop While not sLine.EndsWith("<EOF>")
ErrorCode = 0
Catch ex As SocketException
ErrorCode = 89
response = "SocketException " & ex.SocketErrorCode.ToString & _
" during receive attempt."


Catch ex As Exception
ErrorCode = 88
response = ex.Source & ":" & ex.Message
'Note: The control which displays the error message must
' handle any format issues like no CRLF or max length.
End Try

If bAbort Then
ErrorCode = 88
response = "Send/Receive cancelled by user."
Else
If pClient.Connected Then
response = sLine
Else
Console.WriteLine("Receive failed due to {0}", response)
End If
End If

End Sub 'Receive


Thanks for the suggestion,
Erik Warren

Looking more closely, your doing blocking IO inside of your async callbacks.
You shouldn't be doing that....

I suggest you take a look here:
http://msdn2.microsoft.com/en-us/library/bbx2eya8.aspx
 
E

Engineerik

Tom Shelton said:
Looking more closely, your doing blocking IO inside of your async callbacks.
You shouldn't be doing that....

I suggest you take a look here:
http://msdn2.microsoft.com/en-us/library/bbx2eya8.aspx

The code I wrote is merely a tweaking of the code you referenced. Both look
like blocking code to me.

Nevertheless, I have solved my problem although I don't know why the code
is behaving the way it is. The buffer on the client side was not large
enough. The 1440 byte limit seems to be the packet size used in win 2000.
The server was sending the first packet of 1440 bytes but the client was not
able to receive the first packet quickly enough to satisfy the server. Thus
the next packet was sitting at the server waiting even though I made a second
call to recieve on the client side.
By increasing the buffer size on the client side I found that I could
recieve all the packets from the server and avoid the problem.

With this solution in hand I was able to demonstrate the same behavior in
XP. The packet size in XP is larger so I had to send much larger strings
across the socket in order to trigger this behavior.

Making additional calls to receive on the client side does not seem to help.
Once the server finds the client unready to accept a packet it appears to
wait for a subsequent send call before sending the packet.

Regards,
Erik Warren
 
T

Tom Shelton

The code I wrote is merely a tweaking of the code you referenced. Both look
like blocking code to me.

Take a closer look - they never call Receive in their callbacks - they,
make another call to BeginReceive. Besides, this apparently wasn't the
issue anyway :)
Nevertheless, I have solved my problem although I don't know why the code
is behaving the way it is. The buffer on the client side was not large
enough. The 1440 byte limit seems to be the packet size used in win 2000.
The server was sending the first packet of 1440 bytes but the client was not
able to receive the first packet quickly enough to satisfy the server. Thus
the next packet was sitting at the server waiting even though I made a second
call to recieve on the client side.
By increasing the buffer size on the client side I found that I could
recieve all the packets from the server and avoid the problem.

With this solution in hand I was able to demonstrate the same behavior in
XP. The packet size in XP is larger so I had to send much larger strings
across the socket in order to trigger this behavior.

Making additional calls to receive on the client side does not seem to help.
Once the server finds the client unready to accept a packet it appears to
wait for a subsequent send call before sending the packet.

Regards,
Erik Warren

Interesting... Can you try to set the NoDelay option, and see if this
problem goes away? I'd be curious to know - I've never seen this
behavior you describe...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top