1

In C# (a Unity script), I have a client that uses either an TcpClient to send and receive data. The client will send a fixed data string every "frame" to the server. The server just echoes back that same string. This is testing and simulation purposes.

I use the Async methods BeginWrite and BeginReceive. The data is sent by the client by using:

stream.BeginWrite(data, 0, data.Length, new AsyncCallback(EndTCPSend), null);

And I use the following call to receive data:

TCPClient.GetStream().BeginRead(TCPBuffer, 0, 1024, new AsyncCallback(OnMessageTCP), null);

Now, the problem is that after a short period of time (1 second or so) the client stops sending out data to the server, even though the code that calls the method for sending is still being called (verified through log output and Wireshark). No data is send out, and thus no data is received anymore at the server.

The following code is used to initialize the TcpClient:

TCPClient = new TcpClient();
TCPClient.NoDelay = true;
TCPClient.Connect(remoteEndPoint);
if (TCPClient.GetStream().CanRead)
{
    TCPClient.GetStream().BeginRead(TCPBuffer, 0, 1024, new AsyncCallback(OnMessageTCP), null);
}

Every frame, the following code is used to start sending the string:

NetworkStream stream = TCPClient.GetStream();
if (stream.CanWrite)
{
    byte[] data = Encoding.UTF8.GetBytes(msg);
    stream.BeginWrite(data, 0, data.Length, new AsyncCallback(EndTCPSend), null);
}

And the following method is used to close the async sending:

private void EndTCPSend(IAsyncResult result)
{
    TCPClient.GetStream().EndWrite(result);
}

To receive the data, I use the following method as a callback:

private void OnMessageTCP(IAsyncResult result)
{
    NetworkStream stream = TCPClient.GetStream();
    int read = stream.EndRead(result);

    if (read == 0)
    {
        return;
    }

    string message = Encoding.UTF8.GetString(TCPBuffer, 0, read);
    TCPMessageBuffer += message; // <-- This line seems to cause the problem.
    stream.BeginRead(TCPBuffer, 0, 1024, new AsyncCallback(OnMessageTCP), null);
}

Anyone any idea of what I do wrong here? Any reason why the client stops sending? Can I send and receive data asynchronously like that?

Thanks in advance!

Jan Discart
  • 167
  • 1
  • 1
  • 13
  • Where do you call EndSend? – jgauffin Jul 06 '14 at 16:37
  • I added the code I used to end the sending of the data. This was already present in my code, I forgot to mention it in my question. Thanks for pointing it out. – Jan Discart Jul 06 '14 at 19:41
  • do you try to send to messages at the same time? That can cause an exception. You also might want to catch exceptions in the callbacks as unhandled exceptions in them will crash your application. Why do you call CanRead/CanWrite? – jgauffin Jul 06 '14 at 19:54
  • I send only 1 message per frame, so I think no messages are sent at the same time, tho I'm not sure if it can happen that one message has been completely send while the next one is already ready to be sent. I'll take a look when placing try - catches and report back. I will also try to use a semaphore for reading and writing to the socket, see if that makes a difference. I'll report back later. Thanks for taking a look at this with me. – Jan Discart Jul 06 '14 at 20:42
  • I think the bug is not visible in the code posted. (You have a different bug there - you cannot split UTF8 bytes into parts and decode them separately. You assume that a read will read an entire send buffer.) – usr Jul 06 '14 at 22:41
  • @usr: You're absolutely right. In the code I posted above, I omitted string processing because I thought it was not relevant to the problem. But I commented out one line that processed the extracted string, and suddenly sending and receiving goes as expected. I updated the code in my original question in the method `OnMessageTCP` with the line that seems to cause the problem. The TCPMessageBuffer is just one large string containing a concatenation of all received strings. Any idea on how I should handle extracting this string then? – Jan Discart Jul 07 '14 at 07:55
  • 1
    Use a higher-level format such as protobuf or webservices. If you insist on doing everything yourself use BinaryReader/Writer or even BinaryFormatter. – usr Jul 07 '14 at 07:58
  • @usr I ended up using StringBuilder which seems to work as well. If you can formulate your responses into an answer, I'll gladly accept it. Thanks for your help. – Jan Discart Jul 07 '14 at 08:44

0 Answers0