Click here to Skip to main content
15,890,882 members
Please Sign up or sign in to vote.
5.00/5 (1 vote)
I'm writing some code in C# for the first time which requires talking to a network attached device using HTTP. Unfortunately the device is broken and so I cannot use the HttpWebRequest/HttpWebResponse classes, so I'm having to do it myself with TcpClient and NetworkStream.

I've got the following code:

// make and send the request
byte[] sendBytes = Encoding.ASCII.GetBytes("GET / HTTP/1.1" + Environment.NewLine + Environment.NewLine);
netStream.Write(sendBytes, 0, sendBytes.Length);

// read and display the response
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
int bytesRead = netStream.Read(bytes, 0, tcpClient.ReceiveBufferSize);
Console.Writeline(bytesRead + " bytes read");
string returnData = Encoding.ASCII.GetString(bytes);
Console.Writeline(returnData);


Now I know for certain that my response should be 191 bytes long. However I only get 40 bytes in my bytesRead buffer.

The only way I can make it work is by doing this:

// make and send the request
byte[] sendBytes = Encoding.ASCII.GetBytes("GET / HTTP/1.1" + Environment.NewLine + Environment.NewLine);
netStream.Write(sendBytes, 0, sendBytes.Length);

// sleep while waiting for a complete response
Thread.Sleep(50)

// read and display the response
byte[] bytes = new byte[tcpClient.ReceiveBufferSize];
int bytesRead = netStream.Read(bytes, 0, tcpClient.ReceiveBufferSize);
Console.Writeline(bytesRead + " bytes read");
string returnData = Encoding.ASCII.GetString(bytes);
Console.Writeline(returnData)


Clearly this is ugly and is not robust to different network conditions, so I would like a way to avoid it.

I've tried various things like looping on netStream.DataAvailable and appending any further data but this doesn't get me any further.

Unless I have misinterpreted it, the following sentence from the NetworkStream documentation implies that this kind of messing around isn't necessary:

Read and write operations can be performed simultaneously on an instance of the NetworkStream class without the need for synchronization. As long as there is one unique thread for the write operations and one unique thread for the read operations, there will be no cross-interference between read and write threads and no synchronization is required.

Will anybody suggest an alternative?

Posted
Updated 25-Aug-10 7:52am
v3

Thanks for your answer. I am sure that the incoming message is smaller than the buffer size. I have also tried the approach which is outlined on MSDN and it did not help me. This is what I meant by "looping on netStream.DataAvailable and appending any further data" in my question.

What I have found helps is rather than handle the raw incoming bytes, if I wrap the NetworkStream in a StreamReader and StreamWriter things seem to work without my Thread.Sleep().

My control loop cannot run as quickly in this manner though so I am not sure whether the reader/writer are actually helping me or whether they are just slowing things down enough to avoid the race condition (exactly what the Thread.Sleep() was doing).

In any case this seems to be robust at least.

My code now looks like this:

StreamReader reader = new StreamReader(netStream);
StreamWriter writer = new StreamWriter(netStream);

// make and send the request
writer.Write("GET / HTTP/1.1" + Environment.NewLine + Environment.NewLine);
writer.Flush();

// read and display the response
string returnData = reader.ReadToEnd();
Console.Writeline(returnData)
 
Share this answer
 
I think you probably need to keep reading until there is no more data available. The remote computer may not present the entire response in a single packet so your code should allow for that fact and also use the contents of the response to stop reading when you have the entire message. Take a look at the sample code here[^] for some more information.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900