views:

169

answers:

1

Hi,

Please excuse my choice of wording and/or mixup of terms, I am a dummy when it comes to socket programming. I am trying to connect to a TCP server, write a message and process a response. I use the following code:

Dim tcpClient As Sockets.TcpClient = New TcpClient()

tcpClient.Connect(hostname, 9080)

Dim networkStream As NetworkStream = tcpClient.GetStream()

If networkStream.CanWrite And networkStream.CanRead Then

    Dim sendBytes As [Byte]() = Encoding.ASCII.GetBytes(body)
    networkStream.Write(sendBytes, 0, sendBytes.Length)

    Dim bytes(tcpClient.ReceiveBufferSize) As Byte
    networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))

    Dim returndata As String = Encoding.ASCII.GetString(bytes)
End If

I can see the server logs and notice that the server only ever reads from the socket when I stop debugging. It then processes the message and sends a response (which is a bit late as my client is not listening anymore).

It seems the networkStream object needs to be closed first. However, if I do this I can not process any subsequent response. Do I need to 'signal' to the server that I have finished writing? Do I need to use a different model altogether?

All responses or pointers are much appreciated.

+1  A: 

Closing/disposing the NetworkStream should not be necessary, but I would question the manner in which the data is being sent. Did you write the server? I would expect either a length prefix on the data being sent (and received) or a termination character or phrase. If you just write the data like that, the server can't know how much of the data it should read.

The same goes for the receiving code. You're simply trying to read up to the ReceiveBufferSize rather than using a length being sent to you by the server.

Are you certain that the protocol you're using doesn't include these elements?

Also, bear in mind that Read as with most/all other Stream objects, does not guarantee that you'll get the number of bytes you request. It will read up to that number of bytes and the return value of the function indicates how many were read. You typically have to set up a loop structure to get a specific number. Something like...

int bytesToRead = 1024; // sample
int totalBytesRead = 0;
int bytesRead = 0

while(bytesToRead > 0)
{
    bytesRead = stream.Read(buffer, totalBytesRead, bytesToRead);

    if(bytesRead == 0) throw new Exception("Connection closed");

    totalBytesRead += bytesRead;
    bytesToRead -= bytesRead;
}

This is somewhat more verbose than a typical implementation to give you an idea of what needs to be happening. Something more typical would be:

int bytesToRead = 1024;
int bytesRead = 0;

while((bytesRead += stream.Read(buffer, bytesRead, bytesToRead - bytesRead) <= bytesToRead - bytesRead) { }
Adam Robinson