Search code examples
.netc#-4.0tcptcpclienttcplistener

TcpListener request flood


Hi All: I'm trying to ensure my TcpListener can handle multiple requests from a client properly. I am trying multiple BeginSend method calls inside a for loop and finding that the output from the Listener is inconsistent in terms of how many responses I am getting. i.e. if I call BeginSend 20 times sequentially I would want the Listener to give me 20 responses. Sometimes I get 2, sometimes 3, sometimes more and, it appears, that the messages I send to the Listener are being appended to one another, rather than being treated as separate entities.

Assume I have a valid TcpClient class (see code) which wraps a basic TcpClient and a valid TcpListener class (see code) which responds to a message from a connected TcpClient by raising a DataReceived event with the received message as its argument. Pretty basic code

for(int i = 0; i < 10; i++)
{
    client.Client.BeginSend(Encoding.ASCII.GetBytes(i.ToString()), 0, i.ToString().Length, SocketFlags.None, null, null);
}

I would expect the output from the TcpListener to be
0
1
...
9

Instead I am getting things like:
0
123456789
or,
0
1234
56
789
or,
....
or some other permutation of the 10 separate messages Here is the relevant code for the Listener:

    private void ListenForNewClients()
    {
        Task.Run(async () =>
        {
            while (true)
            {
                var tcpClient = await tcpServer.AcceptTcpClientAsync();

                clients.Add(tcpClient.Client);
                tcpClient.Client.BeginReceive(buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, tcpClient.Client);

            }
        });
    }

And the ReceiveCallback:

    private void ReceiveCallback(IAsyncResult ar)
    {
        var tcpClient = ar.AsyncState as Socket;
        try
        {
            var bytesRead = tcpClient.EndReceive(ar);

            if (bytesRead == 0)
            {
                tcpClient.EndReceive(ar);
            }

            var data = Encoding.ASCII.GetString(buffer, 0, bytesRead);

            DataReceived?.Invoke(this, data);

            buffer = new byte[BufferSize];
            tcpClient.BeginReceive(buffer, 0, BufferSize, SocketFlags.None, ReceiveCallback, tcpClient);

        }
        catch
        {
            clients.Remove(tcpClient);
        }
    }

Solution

  • it appears, that the messages I send to the Listener are being appended to one another, rather than being treated as separate entities.

    That's how TCP/IP works.

    If you are writing both the client and server, then I recommend using SignalR, which preserves message boundaries.

    If you must use TCP/IP, then you'll need some form of message framing.