Asynchronous socket woes

From: Rick Elliott via .NET 247 (anonymous_at_dotnet247.com)
Date: 08/04/04


Date: Wed, 04 Aug 2004 05:06:01 -0700

I tried posting this issue last week, but it never showed up on the list. My apologies if I've created a duplicate.

Hello, there. I'm a relative newbie to .NET and certainly a greenhorn on the finer points of socket programming and I'm running into some trouble. I'm trying to create a class (no UI) that allows an application to communicate with a server by sending and receiving protocols (I guess you could term my class as a client since I'm not accepting connections, just establishing one to the server). In my class, I'm using asynchronous calls (i.e. BeginSend, EndSend, BeginReceive, EndReceive) to send and receive data since I don't want the application hanging while data is being sent/received.

I've established a connection successfully and can send and receive data. However, I appear to be receiving chunks of data out of order on occasion (i.e. I added a packet number to my buffer object that I use for the BeginReceive/EndReceive calls, and I get it back in a sequence similar to 1,2,3,4,6,5,7,9,8) which really screws up my app (it's not good to receive an XML document in a semi-chopped up fashion ;-). I'm quite sure I'm doing something goof, but I've been banging my head against the wall for the past two days trying to figure it out. Here's a quick rundown on what I'm using:
* Using TCP socket in Stream mode. The socket is blocking.
* Using 256 byte buffer to receive data. Have tried other sizes but hasn't made a difference that I can tell (I tried a one byte buffer for grins and it exhibits the same behavior, actually makes it easier to exhibit the problem, which makes sense).
* Converted to use NetworkStream instead of using Socket directly (use BeginRead/EndRead calls), but no luck. This is what I'm currently using.

Here are my send and receive methods, plus my socket and stream setup:

...
// Create new instance of socket
mSocket=new Socket(AddressFamily.InterNetwork,SocketType.Stream,ProtocolType.Tcp);
mSocket.Blocking=true;
...
// Create new instance of network stream for all socket communication
mStream=new NetworkStream(mSocket,System.IO.FileAccess.ReadWrite,false);
...
public void Send(string appId, string command, string data)
{
  try
  {
  // Construct the information to be sent to the server
  byte[] SendData = Encoding.Default.GetBytes(appId+mDelimiter+command+mDelimiter+data+mEOM.ToString());

  Console.WriteLine("Sending Data: {0}",appId+mDelimiter+command+mDelimiter+data+mEOM.ToString());

  // Start sending the data to the server
  mStream.BeginWrite(SendData,0,SendData.Length,mSendCallback,mStream);
  }
  catch (Exception e)
  {
  // TODO: Add exception handling to Send method
  Console.WriteLine(e.ToString());
  }
}

private void OnSend(IAsyncResult result)
{
  // Get the socket that sent the data
  NetworkStream SendStream=(NetworkStream) result.AsyncState;

  // Complete the send operation
  SendStream.EndWrite(result);

  // Start listening for data from the server
  Receive();
}

private void Receive()
{
  try
  {
  // Create object to receive the information from the server
  DataPacket ReceiveState=new DataPacket(mStream,mBufferSize);

  // Set the packet number
  ReceiveState.PacketNumber=++mPacketCount;

  // Start receiving information from the server
  mStream.BeginRead(ReceiveState.Buffer,0,mBufferSize,mReceiveCallback,ReceiveState);
  }
  catch (Exception e)
  {
  // TODO: Add exception handling to the Receive method
  Console.WriteLine(e.ToString());
  }
}

private void OnReceive(IAsyncResult result)
{
  try
  {
  // Get the object that contains the received data
  DataPacket ReceiveState=(DataPacket) result.AsyncState;

  // Get the stream that is receiving the data
  NetworkStream ReceiveStream=ReceiveState.Stream;

  // End the current receive operation
  ReceiveState.Length = ReceiveStream.EndRead(result);

  Console.WriteLine("Data Packet {0}: {1}",ReceiveState.PacketNumber,ReceiveState.ToString());

  if (ReceiveState.Length > 0)
  {
    // Make sure our call back is established
    if (mCallbackObject != null)
    {
    // Process the received message
    ProcessData(ReceiveState);
    }

  // Listen for more data
  Receive();
  }
  else
  {
  // Close the socket connection
  Close();
  }
  }
  catch (ObjectDisposedException e)
  {
  // Close the socket
  Close();
  }
}

Any thoughts on how I could be goofing this up would be happily accepted. I've scoured several sites and looked at several examples, but I can't see what I'm doing wrong. Hopefully it is something easy. If more source is required to help see the issue, I will happily send the class with the whole deal in it. Thanks.
--------------------------------
From: Rick Elliott

-----------------------
Posted by a user from .NET 247 (http://www.dotnet247.com/)

<Id>1D7NuB7tmUel+3NwSTnSTQ==</Id>



Relevant Pages

  • Re: How do I stop a Winsock from buffering characters?
    ... it's applied at the OS level to the socket. ... Stream s = client.GetStream; ... from the client code and have the server see it right away. ... first character of the client send. ...
    (microsoft.public.windowsce.embedded)
  • Concurrent reader/writer threads on single socket
    ... I have what I imagine is a well-known .Net networking problem, ... one dedicated to reading from the socket and the other one ... BinaryWriter writer = new BinaryWriter); ... the output stream would hold a separate buffer ...
    (microsoft.public.dotnet.general)
  • Re: std::cin and disabling canonical line processing (buffering)
    ... I believe I have found a couple of implementations of sockets in streams but ... > * create the streambufs, istream, and ostream around that socket ... >> I have a program that runs a command line interface on an embedded system. ... >> function is just given the stream pointers. ...
    (microsoft.public.vc.stl)
  • Re: Im having problems with cryptography and sockets, help
    ... If the sender does not send 8192 bytes, the call to Read is going to ... I am> using blocking sockets, so I am aware that if the socket does not have ... But I know that it does receive> the data, and still it blocks, not the NetworkStream, but the CryptoStream> used to decrypt the data. ... > NetworkStream stream = clienteTcp.GetStream;> // Crear el stream criptográfico ...
    (microsoft.public.dotnet.languages.csharp)
  • Re: std::cin and disabling canonical line processing (buffering)
    ... create the streambufs, istream, and ostream around that socket ... The problem with socket-in-a-streambuf is that it is not possible to call socket functions and such on it, but if you only need the stream temporarily as an "interface" of sorts, then you can do all of the socket stuff in the calling function. ... The user can access this via telnet or via an RS232 port that the system will treat as a console. ... In the embedded system, a task is spawned and the task function is just given the stream pointers. ...
    (microsoft.public.vc.stl)