Thursday, November 4, 2010

Flush Socket in .NET or C# to ensure send of acknowledgement

Today, I faced a problem regarding synchronizing a C# TCP/IP Client with a JAVA 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.


the .Net Socket Send page (http://msdn.microsoft.com/en-us/library/ms145160.aspx) has the following:


"There is also no guarantee that the data you send will appear on the network immediately. To increase network efficiency, the underlying system may delay transmission until a significant amount of outgoing data is collected. A successful completion of the Send method means that the underlying system has had room to buffer your data for a network send."

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)

I tried to 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 according to their site...


This is my code in case you are really really curious


Instead of doing 


 //first send an acknowledgement to client  saying we are good...Now you can stop
          const string sendData = "< response status="\" > success < / response >";
                      byte[] bytes = Encoding.UTF8.GetBytes(sendData);
                      if (listenerSocket != null)
                      {
                          listenerSocket.Send(bytes, bytes.Length, 0);
                      }



I am doing ....



     NetworkStream ns = new NetworkStream(listenerSocket);
            StreamWriter w = new StreamWriter(ns);
          const string sendData = "< response status="\" > success < / response >";
            string message;
            try
            {
                w.Write(sendData);
                w.Flush();
                message = String.Format("\n\nPOST successful. bytes sent " + xml.Length);
            }
            catch (Exception ex)
            {
                message = String.Format("\n\nPOST failed. Received exception {0}", ex);
            }
            finally
            {
                w.Dispose();
                ns.Dispose();
            }

And yet the server does not receive any acknowledgment. I am very clueless at this point and any suggestion would be more than welcomed.

Update:

I think I have figured out a solution

This send code seems to be working in my case


 //--trying the asynchronous thing
IAsyncResult ar = listenerSocket.BeginSend(asen.GetBytes(xml), 0, xml.Length, SocketFlags.None, null, null);
listenerSocket.EndSend(ar);
string message = String.Format("\n\nPOST successful. bytes sent " +ar.ToString()+"\n"+ xml.Length);


Hope it works for you as well

1 comment:

Anonymous said...

What worked for me: my C# send buffer had to end with a byte equal to 0.