Tuesday, February 27, 2007

Flush Socket in .NET or C#

Today, I faced a problem regarding synchronizing TCP/IP Client with TCP/IP server.
The problem was, client sends data and waits for acknowledgment. Server listens for data and when it gets data, it sends acknowledgment to the client and start listening for data again. Now when server starts listening for data again it gets old data i.e. it was not getting blocked on the read() function which it should, as client hasn't send any more data.

So, the problem was that the data was not being flushed. I searched for Flush method in System.Net.Sockets.Socket class but it was not there. There was a suggestion like:

1. Use the SetSocketOption function and set the value of ReceiveBuffer option to 0. It didn't work. Though the recivebuffer length was 0, the data was still being buffered.
2. Use the IOControl function to set the value for Flush option. But you won't find the integer value for Flush Option (atleast I was not able to)

The solution is, use NetworkStream class. You create a new stream using socket and then you create StreamReader and StreamWrite object using NetworkStream object

NetworkStream stream = new NetworkStream(socket);
StreamReader sr = new StreamReader(stream);
StreamWriter sw = new StreamWriter(stream);

Then, use Flush() method of StreamWriter to flush the data. You can also set the property called AutoFlush of StreamWriter to automatically flush the stream after write operation. But Flush() method is more reliable.

3 comments:

Anonymous said...

No. Flush has no effect.

From http://msdn.microsoft.com/en-us/library/system.net.sockets.networkstream.flush.aspx

"The Flush method implements the Stream..::.Flush method; however, because NetworkStream is not buffered, it has no affect on network streams."

Anonymous said...

The previous comment does not understand what Angrez mean.
I have struggled with this issue for a week and this solution works perfectly.
Instead of sending and encoding byte-arrays with risc of not getting all data at once you can use StreamReader and StreamWriter.

I will share a little piece of my code.

My original write code:
sendBytes = Encoding.Unicode.GetBytes(responseString)
networkStream.Write(sendBytes, 0, sendBytes.Length)
My corresponding new code:
sw.Write(responseString)
sw.Flush()

My original read code:
networkStream.Read(bytes, 0, CInt(tcpClient.ReceiveBufferSize))
clientdata = Encoding.Unicode.GetString(bytes)
My corresponding new code:
sr.Read(C, 0, CInt(tcpClient.ReceiveBufferSize))
clientdata = New String(C)

Many thanks!

substans said...

what about the Socket.NoDelay Property ?