Title: Where are TCP ACKs sent and how to have them sent faster
Tags: .net;sockets;tcp;garbage-collection
Question: From answers to other questions I learned that the OS/TCP stack is responsible for sending ACKs. In which process does this happen?
Can a System.Net.Sockets.Socket object that is used for TCP be configured in a way that it sends ACKs as soon as possible, preferably independent of garbage collections?
Background and Details:
I have an .NET application that receives data from a device using TCP with a direct network connection from the computer to the device.
The device creates data constantly with about 30 MB/s, and sends them over the network. It uses a buffer to store TCP packets until it receives an ACK. When the buffer overflows, the device stops with an error. Unfortunately, the buffer is only a few kB in size what means that ACKs have to be sent within a few milliseconds.
The device works as it is, I cannot change it, and I have to deal with it.
This worked fine for several years with a relatively simple native program, but with the object oriented and more complicated .NET app, it is not running stable, and I have some suspect that sometimes when the garbage collector runs, ACKs might not be sent quickly enough.
Now there are several things that I could change (e.g. change socket settings, change GC settings, make less allocations, or more drastic things like putting a switch between the device and the computer). My attempts so far have not been successful (except the switch), and this is why I would like to understand what’s going on.
I set Socket.NoDelay = true.
Question:
Are ACKs being sent within the process of the application or in a different process? If within the process, is this influenced by the .NET garbage collector? What can be done to have ACKs sent faster?
Comment: *"afaik all modern Windows versions ignore it."* - well, he could run it under linux, where you can tweak socket buffer sizes. ¯\\_(ツ)_/¯

Comment: @HansPassant Is the kernel buffer that what can be set with `ReceiveBufferSize`? If not, is there a way to increase it? (Btw I agree with what you wrote about millisecond service time, but unfortunately I have to make the best of it.)

Comment: @C.Gonzalez True, it can easily handle 300 MB/s, the problem obviously only are short (milliseconds?) pauses, maybe including garbage collector, and with this I think a larger buffer would be helpful.

Comment: @HansPassant The rate is not an issue. Thank you for your hints, it makes sense now.

Comment: It happens in the TCP/IP driver stack, not a process.  Neither .NET nor the GC has any direct affect on it.  But TCP does throttle, ACKs are delayed when the kernel buffer fills up to capacity.  So a simple fire-hose problem is an explanation, if the program doesn't call Socket.Read() often enough or sips from the hose with a byte[] that is too small then the device is liable to run into trouble.  Demanding millisecond service time from *any* userland program and not throttling on the device side is almost inevitably going to be a problem.

Comment: Only theoretically, afaik all modern Windows versions ignore it.  Buffer size is never a solution to a fire-hose problem, if the app only can read at a 29 MB/sec rate then no buffer is ever going to be big enough.

Comment: On the otherr hand, even under .net, a dedicated consumer thread (emptying the queue and filling up some secondary buffer) should be able to handle 30MB/s with relative ease I´d assume.



{'source': 'StackExchangeDataset', 'subset': 'stackoverflow.com', 'metadata': {'AnswerCount': 0, 'CommentCount': 7, 'ContentLicense': 'CC BY-SA 3.0', 'CreationDate': '2017:00:10/05/17', 'FavoriteCount': None, 'PostTypeId': 1, 'Tags': '<.net><sockets><tcp><garbage-collection>', 'Title': 'Where are TCP ACKs sent and how to have them sent faster', 'ViewCount': 201, 'id': 46581641, 'user_AboutMe': '', 'user_AccountId': 2046225.0, 'user_DisplayName': 'Martin', 'user_Reputation': 1908.0, 'user_Views': 147.0, 'user_id': 1826253.0}}