Operating System - OpenVMS
1753936 Members
9788 Online
108811 Solutions
New Discussion юеВ

Windows socket client drops the last byte of every packet

 
tsgdavid
Frequent Advisor

Windows socket client drops the last byte of every packet

I am having trouble with a socket client application written in vb.net using Visual Studio 2005. The client connects to a C language socket server that is running on OpenVMS. The problem that I have is that when the server sends a packet, the client does not receive the last byte (of every packet!). I can dump the packets on the network and the data is all there. My current solution is to keep my socket messages short (247 bytes) and send one extra byte past the end of my data.

I would like to include more information in my messages and I cannot find a way to make this work. If I knew 100% how long the packets will be on the network, I could work around this by including an extra byte in just the right places. However, I don't want to make any assumptions about the length of the packets.

Does anyone have any suggestions about what the best solution is to this problem?
12 REPLIES 12
Joseph Huber_1
Honored Contributor

Re: Windows socket client drops the last byte of every packet

How does the client know the length of one message or record ? (I would not call it 'packet', since this is the unit the low level TCP/IP layers are exchanging the data).

Can You show us the loop done on the receiver(select,recv,read)?

Basically there two ways for a protocol:
(1) the protocol is 'binary': each message starts with a byte (or word-)count, and the receiver reads until the counted bytes are read.
(2) the protocol is (ascii-)text based: then usually the receiver reads until a terminator sequence (usually or ) received.

http://www.mpp.mpg.de/~huber
tsgdavid
Frequent Advisor

Re: Windows socket client drops the last byte of every packet

Below is a copy of my code. After revisiting this, I am thinking that maybe, the problem is the offset which is the 2nd argument to ClientSocket.Recieve. I probably need to look at this a little closer.

Private Sub ReceiveMsg()
Dim nTotalBytes As Integer
Dim nNumBytes As Integer
Dim nMsgType As Short
Dim nMsgLen As Short
Dim ind As Integer

Try
nNumBytes = -1
While (nNumBytes <> 0)

nTotalBytes = 0
RecvBuffer.Initialize()

nNumBytes = ClientSocket.Receive(RecvBuffer, nTotalBytes, 4, SocketFlags.None)
If nNumBytes > 3 Then
SyncLock ClientSocket
AppendText("")
AppendText("Message Received " & Str(nNumBytes) & " Bytes")
nTotalBytes = nTotalBytes + nNumBytes
nMsgType = BitConverter.ToInt16(RecvBuffer, 0)
nMsgLen = BitConverter.ToInt16(RecvBuffer, 2)
If nMsgLen > 8191 Then
AppendText(" Error - Message length invalid: " & Str(nMsgLen))
nMsgLen = 250
End If

While (nTotalBytes < nMsgLen And nNumBytes > 0)
nNumBytes = ClientSocket.Receive(RecvBuffer, nTotalBytes, (nMsgLen - nTotalBytes), _
SocketFlags.None)
AppendText("Message Received " & Str(nNumBytes) & " Bytes")
nTotalBytes = nTotalBytes + nNumBytes
End While
End SyncLock

AppendText("Total Bytes Received = " & Str(nTotalBytes))
AppendText("MsgLen from Message = " & Str(nMsgLen))
Select Case nMsgType
Case 1
AppendText(" Liftpos = " & System.Text.Encoding.ASCII.GetString(RecvBuffer, 4, 1))

For ind = 0 To NUM_LOCATIONS - 1
SlabNo(ind) = System.Text.Encoding.ASCII.GetString(RecvBuffer, 5 + (ind * 12), 12)
Next

RefreshScreen()

Case Else
AppendText(" Unrecognized message type: " & Str(nMsgType))

End Select

End If
End While


Catch ex As Exception
' Tell the main thread to invoke DisconnectedUI
Dim cb As New SimpleCallback(AddressOf DisconnectedUI)
Me.Invoke(cb)
Return
End Try
Hoff
Honored Contributor

Re: Windows socket client drops the last byte of every packet

You are aware that there are no packets with TCP, and that your code is entirely responsible for waiting for the characters to arrive from the stream, and for building up and chunking up the "packets" from one or more I/O calls before using the contents of the "packet"?

Now UDP? UDP has packets; one message, one datagram. You either get the message, or you don't. If you don't, you resend.

If this isn't the usual case of processing a stream into packets (and a late-arriving byte), and your code is doing assembly and disassembly as the data arrives, then your code probably has a bug. The numbers of different ways this can go off the rails is large; C and BASIC differ in how they index stuff, and C is quite fond of off-by-one bugs, or any number of other bug-like creatures in the respective critter zoos of C and BASIC.

It's also possible the underlying code has a bug, though any bugs lurking in an IP stack transport tend to show up all over the place; all sorts of stuff breaks.

I'll also mention that the underlying problems here have long been solved, as have most of the related problems of recovery and restarts and related. Writing socket code was commonplace a quarter century ago (and many of us suffered through the "fun" of debugging that stuff), but there are now good libraries and transports that can deal with this dreck. Even on VMS. I'd suggest looking at zeroMQ (0MQ) as a starting point, though there are various other options.
tsgdavid
Frequent Advisor

Re: Windows socket client drops the last byte of every packet

Thanks for your comments. I think I have a program bug.
tsgdavid
Frequent Advisor

Re: Windows socket client drops the last byte of every packet

OK, It has been a while since I abandoned this, so I have spent some time running with the debugger to review what is happening:

1) VMS socket server sends a QIOW with the message length (400) encoded in the message. However, the length specified on the QIOW is 402.

2) Windows vb.Net client receives 4 bytes from the stream to get the msg type and msg length. It sees that the msg length is 400

3) Windows vb.Net client calculates the size of the rest of the message (400 - 4 = 396) and then receives 396 bytes.

4) The data received is missing two bytes of the data that was sent, but is happy because it thinks it is only supposed to receive 400 bytes instead of 402. It then waits for more data.

By Using TCPTRACE on OpenVMS, I see the stream of bytes split into two packets. The missing bytes are the last byte included in each packet. All of the data can be viewed in TCPTRACE, but the vb.Net client does not receive it. FYI the code pasted above is slightly different than the code I am currently using to try to test longer messages, but it operates the same way. (Meaning that I send 248 bytes with an encoded msg length of 247. I only add one extra byte, because the client only drops one byte due to the entire message being sent in a single packet.)

My client receives multiple messages that are identical with the exact same results every time.

If someone wants to see the details, I can send the current client code and the TCPTRACE output.
Joseph Huber_1
Honored Contributor

Re: Windows socket client drops the last byte of every packet

>>1) VMS socket server sends a QIOW with the message length (400) encoded in the message. However, the length specified on the QIOW is 402.

And what if You simply agree with the servers message format, and interpret the QIO length as "inclusive count", i.e.
402 = 2 byte count field, followed by 400 data bytes ?
http://www.mpp.mpg.de/~huber
Joseph Huber_1
Honored Contributor

Re: Windows socket client drops the last byte of every packet

>>client calculates the size of the rest of the message (400 - 4 = 396) and then receives 396 bytes.

Isn't it as simple as
400-2=398, and then the complete message is read ?
In other words, the message length field does only count itself and the data, not the preceding type code word ?
http://www.mpp.mpg.de/~huber
tsgdavid
Frequent Advisor

Re: Windows socket client drops the last byte of every packet

Possibly I was not clear. Let me try again.

My Header (msg type/ msg size) is 4 bytes. The encoded length is inclusive, but this does not matter as long as the client knows whether the encoded length includes the header or not. I suppose it would be a little simpler on the client if it did not count the header.

The main point is this:
- If The QIOW has a length of 248 bytes, the client only receives 247. The last byte is missing.

- If the QIOW has a length of 402 bytes, the client only receives 400. It does not get one byte somewhere in the middle of the message or the very last byte.

I can't fathom what could cause this, since I know the data was delivered.

Right now I am trying, as a work around, to send two short messages so that I can be fairly certain that the last byte of each message will be dropped and not make any guesses about how big the packets will be.

This client has been run on multiple Windows XP systems and all operate the same way.

Thanks for your comments.

Dave Williams
Hoff
Honored Contributor

Re: Windows socket client drops the last byte of every packet

There is no correspondence of the number of read requests required to receive a message to the number of write requests needed to send that message.

There is no one-to-one mapping of reads to writes in TCP.

This is a fundamental aspect of how TCP works.