1

I use a TCP socket via localhost to pass data between my C#/Mono program and a Python script, on Raspbian. The data is about 64k bytes. The problem is that not all bytes are sent. The maximum number of bytes sent is 49152. I expect them to arrive in a single packet.

My code:

tcpListener = new TcpListener(ip, port);
tcpListener.Start();
tcpClient = tcpListener.AcceptTcpClient();
tcpClient.SendBufferSize = 1000000;
tcpClient.ReceiveBufferSize = 1000000;
networkStream = tcpClient.GetStream();

I've tried both of the following methods to write data, but neither send all bytes.

tcpClient.Client.Send(byteArray, byteArray.Length, SocketFlags.None);
// OR            
while (!networkStream.CanWrite)
{
     Thread.Sleep(50);
}
networkStream.Write(byteArray, 0, size);

Currently I use two successive transmissions to send the data to the script.

Is this a Mono bug? Or am I doing something wrong here?

Cristian M
  • 715
  • 2
  • 12
  • 32
  • And how do you know not all bytes are sent? Maybe you assume that all data arrives in a single "packet"? – Evk Feb 27 '18 at 10:30
  • @Evk Yes. I expect them to arrive in a single packet. – Cristian M Feb 27 '18 at 10:38
  • 1
    Then you should know TCP doesn't work like this. You are sending 64k bytes but they can arrive at client separately. For example, first 10K bytes arrive, then after some time another 5K, then the rest. So your client should be prepared for this and read from socket until full "message" arrives. – Evk Feb 27 '18 at 10:39
  • @Evk OK. Maybe you can post the comment as an answer so I can mark it. – Cristian M Feb 27 '18 at 10:44

1 Answers1

1

I have encountered this issue before. Basically, you need to take into consideration how network operations actually work.

When you do

networkStream.Write(byteArray, 0, size);

Yes, you are writing it to the stream, but the stream needs to remain open until the client has finished receiving the data.

In my case- I was sending data, then assuming that the networkStream.Read operation had finished, and then closing the connection on the 'Write' side.

If the client doing the writing closes the connection, after they 'think' the file/data has been wrote, but before the receiver has actually 'read' the data, then you can run into instances where parts of the data are lost.

The way to solve this is to create a protocol with your networking.

A common strategy is to measure the amount of data you wish to send and then send that ahead of the payload as a long variable. The receiver will then know how much data is expected and will read that amount of data from the stream. Once finished, the receiver should let the client know that they have received all the data.

The writing client can be 'waiting' for this acknowledgement message in order to keep the stream awake.

One of the earlier solutions I used was :

while (client.IsConnected())
       {
            System.Threading.Thread.Sleep(100);
       }

Right after sending a large file. Then I rely on the receiver to terminate the connection themselves. If the connection is terminated, it would,in my case, be the signal I needed to know that the file had finished transmitting.

Baaleos
  • 1,703
  • 12
  • 22