简体   繁体   中英

TcpClient / Server NetworkStream skipping packets

At some points in my program I have these moments where writes are made almost concurrently from different treads to the server. I have noticed that when both are sent almost immediately one of them never reaches the server despite using TCP which should make sure that the packet is received.

To test this I've simply sent 1000 packets one after another, with no delay:

NetworkStream stream = server.GetStream();
int i = 0;
while (i < 1000)
{
    byte[] data = Encoding.Unicode.GetBytes(i.ToString() + "$");
    stream.Write(data, 0, data.Length);
    i++;
}

and receive:

bool LostConnection = false;
NetworkStream stream = client.GetStream()

while (ClientSocket.Connected && !LostConnection && !AppIsClosing)
{
    try
    {
        byte[] ReceivedBytes = new byte[4096];

        if (stream.Read(ReceivedBytes, 0, ReceivedBytes.Length) == 0)
        { LostConnection = true; break; }
        string DataFromClient = Encoding.Unicode.GetString(ReceivedBytes);

        if (DataFromClient.Contains("$"))
        {
            DataFromClient = DataFromClient.Substring(0, DataFromClient.IndexOf("$"));
            Console.WriteLine(" >> " + DataFromClient);
        }
    }
    catch { }
}

Output:

 >> 0
 >> 1
 >> 20
 >> 76
 >> 108
 >> 136
 >> 163
 >> 197
 >> 220
 >> 241
 >> 276
 >> 302
 >> 330
 >> 372
 >> 373
 >> 469
 >> 507
 >> 530
 >> 560
 >> 590
 >> 628
 >> 651
 >> 683
 >> 722
 >> 747
 >> 772
 >> 803
 >> 826
 >> 861
 >> 889
 >> 913
 >> 950
 >> 980

What could be causing this phenomenon?

PS I've also tried:

var result = stream.WriteAsync(data, 0, data.Length);
result.Wait();

No luck...

Update:

Ok Im stupid. The stream contains all of the other text piled up and I just remove it with the Substring(0, IndexOf("$")) So now I simply replace $ with new line but then I get another problem. Somewhere around 800-900 it starts counting from 500 again and then reaches 999. What could be doing this?

Big serious suggestion, go read and understand this link . You need to send, with your data, some metadata about what you are sending. like how many bytes you are sending. If you send "555$" then you have to prefix this by saying: I'm sending 4 bytes. You need to have a listener that understand that and wait for 4 bytes.

I'm quoting the link above here

Okay, so let's think about the possible situations that 
might occur with the data that the server receives in one receive operation:
  1. On the first receive op, receive less bytes than the length of the prefix.
  2. After having the received part of the prefix on a previous receive op or ops, then receive another part of the prefix, but not all of it.
  3. After having received part of the prefix on a previous receive op or ops, then receive the rest of the prefix, but nothing more.
  4. After having received part of the prefix on a previous receive op or ops, we then receive the rest of it, plus part of the message.
  5. After having received part of the prefix on a previous receive op or ops, we then receive the rest of it, plus all of the message.
  6. Receive exactly the number of bytes that are in the prefix, but nothing more.
  7. After having received exactly the number of bytes that are in the prefix on a previous receive op or ops, we then receive part of the message.
  8. After having received exactly the number of bytes that are in the prefix on a previous receive op or ops, we then receive all of the message.
  9. Receive the number of bytes for the prefix plus part of the message, but not all of the message.
  10. After having received the prefix and part of the message on a previous receive op or ops, we then receive another part of the message, but not all of it.
  11. After having received the prefix and part of the message on a previous receive op or ops, we then receive all the rest of the message.
  12. Receive the number of bytes for the prefix plus all of the message on the first receive op.

The last one is actually the most common thing that will happen. But all of the above things can happen and do happen. If both client and server have buffer sizes larger than the messages, then the situations above may not happen when running both the client and the server on the same machine, or even on a LAN. But TCP is more unpredictable over the Internet where the data passes through multiple machines. So your code needs to allow for all of those possibilities.

I think the problem is this line

        DataFromClient = DataFromClient.Substring(0, DataFromClient.IndexOf("$"));

You are assuming that you will get 1 string per read but there are probably many available on a single read. You should try to use split("$") instead and write all of the results

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM