Asynchronous socket woes

Jul 9 2004 11:14 AM
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.