Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Socket BeginReceive / EndReceive capturing multiple messages

Tags:

c#

sockets

Problem:

When I do something like this:

for (int i = 0; i < 100; i++)
{
    SendMessage( sometSocket, i.ToString());
    Thread.Sleep(250); // works with this, doesn't work without
}

With or without the sleep the server logs sending of separate messages. However without the sleep the client ends up receiving multiple messages in single OnDataReceived so the client will receive messages like:

0, 1, 2, 34, 5, 678, 9 ....

Server sending Code:

private void SendMessage(Socket socket, string message)
{
    logger.Info("SendMessage: Preparing to send message:" + message);            

    byte[] byteData = Encoding.ASCII.GetBytes(message);

    if (socket == null) return;
    if (!socket.Connected) return;

    logger.Info("SendMessage: Sending message to non " +
                "null and connected socket with ip:" + socket.RemoteEndPoint);

    // Record this message so unit testing can very this works.

    socket.Send(byteData);
}

Client receiving code:

private void OnDataReceived(IAsyncResult asyn)
{
    logger.Info("OnDataReceived: Data received.");

    try
    {
        SocketPacket theSockId = (SocketPacket)asyn.AsyncState;
        int iRx = theSockId.Socket.EndReceive(asyn);
        char[] chars = new char[iRx + 1];
        System.Text.Decoder d = System.Text.Encoding.UTF8.GetDecoder();
        int charLen = d.GetChars(theSockId.DataBuffer, 0, iRx, chars, 0);
        System.String szData = new System.String(chars);

        logger.Info("OnDataReceived: Received message:" + szData);

        InvokeMessageReceived(new SocketMessageEventArgs(szData));

        WaitForData();  // .....  

Socket Packet:

public class SocketPacket
{
    private Socket _socket;
    private readonly int _clientNumber;
    private byte[] _dataBuffer = new byte[1024]; ....

My hunch is it's something to do with the buffer size or its just the between the OnDataReceived and EndReceive we're getting multiple messages.

Update: It turns out when I put a Thread.Sleep at the start of OnDataReceived it gets every message. Is the only solution to this wrapping my message in a prefix of length and an string to signify the end?

like image 884
Luke Belbina Avatar asked Aug 16 '26 06:08

Luke Belbina


1 Answers

This is expected behaviour. A TCP socket represents a linear stream of bytes, not a sequence of well-delimited “packets”. You must not assume that the data you receive is chunked the same way it was when it was sent.

Notice that this has two consequences:

  1. Two messages may get merged into a single callback call. (You noticed this one.)
  2. A single message may get split up (at any point) into two separate callback calls.

Your code must be written to handle both of these cases, otherwise it has a bug.

like image 74
Timwi Avatar answered Aug 18 '26 20:08

Timwi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!