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.