Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

socket.send appends packets together even after Tcpclient.NoDelay = true;

Tags:

c#

tcp

sockets

This is starting to frustrate me quite a bit because no matter what I do, my packets get shoved together making it annoying to have to differentiate between them on the other end (objects are easy, variable strings can be a pain). Is there a way to avoid this?

Here is a some crude code I am working with (yes, initialization happens here, this is rough test code so sorry about the poor programming conventions)

    sender.Connect("localhost", 8523);
    sender.Client.SendTimeout = 1000;
    sender.NoDelay = true;
    byte[] buffer = ASCIIEncoding.ASCII.GetBytes(message);
    sender.Client.Send(buffer);
    buffer = ASCIIEncoding.ASCII.GetBytes("DISCONNECT");
    sender.Client.Send(buffer);
    sender.Client.Close();

As you can see two sends happen one after the other and the socket decides that it would be optimal to send them together. That great, but I don't want that. Thus on the other end it ends up being

   helloDISCONNECT

I need the two to be received in separation as they are automatically loaded into a blocking queue and I don't want to deal with object sizes and string parsing.

like image 889
Serguei Fedorov Avatar asked Jan 30 '26 20:01

Serguei Fedorov


2 Answers

TCP presents a stream of bytes to the receiver.

Until the stream is closed, each read of a TCP socket can return between 1 and the size of the buffer that you have given it. You should code accordingly.

TCP does not know, or care, about your program's concept of message framing. It does not care that you send 3 "messages" with separate calls to send. A valid TCP implementation could return a single byte for each call to a function that reads from the stream or it could buffer up as much as it feels like before returning bytes to you. You should code accordingly.

If you want to deal in terms of messages when sending over TCP then you MUST apply your own framing and you MUST deal with that framing yourself when you read your messages. This generally means either a length prefix of a known size or a message terminator.

I deal with this in more detail here, and though the code is in C++ the concepts still apply.

like image 77
Len Holgate Avatar answered Feb 02 '26 10:02

Len Holgate


It appears you expect:

sender.NoDelay = true;

To essentially mean that:

sender.Client.Send(buffer);

...to be a blocking call until the bits are off your NIC. Unfortunately, this is not the case. NoDelay only tells the network layer to no wait, but the underlying call you are making with Send has some async behavior and your program's thread runs quickly enough that the network layer's thread does not wake up before you've essentially appended the second string.

Read more about NoDelay here. Read the remarks there for details.

Some quotes that are relevant:

Gets or sets a Boolean value that specifies whether the stream Socket is using the Nagle algorithm.

The Nagle algorithm is designed to reduce network traffic by causing the socket to buffer small packets and then combine and send them in one packet under certain circumstances

BESIDES, even if you could promise the bits to leave, the client's network layer may buffer them anyways before your client code even has a chance to see there were two "packets".

like image 33
payo Avatar answered Feb 02 '26 11:02

payo