Synapse Telnet delay on Windows XP lazarus / 38-Networking and Web Programming ---------------------------------------------------------------------- VitalArt · 2016-06-10 14:03 Hello,     So I'm developing a program to communicate to a device through Telnet with Synapse TTelNetSend. Basically I send a short (9 characters) command to the device and then receive a slightly longer (~30 characters) response. Through trial and error I figured out that the device needs ~80 ms to send the answer, so I receive 11-12 responses a second. On my Win 8 machine, that is. On Windows XP I only receive 3 - 4 responses a second, and any request sent with timeout < 250 ms times out, while in edge cases I need to poll the device at least 10 times per second.     Through Google I found several discussions like this:http://stackoverflow.com/questions/3818345/telnet-performance-in- windows-xp-and-linux. It appears that if a TCP packet is too small, Windows XP waits 200 ms before finally sending it. I kind of confirmed this theory by forcing my device to send responses to the pc on its own, without a command from the pc by running a macro on it (but I want to avoid actually using macros for the device in my program). The device could send at least 11 responses per second this way, so the delay really does happen when the pc sends the command.     The remedy to this seems to be an option TCP_NODELAY passed to setsockoption (fpsetsockoption in rtl). My question is how do I do that in Synapse? If it's impossible, is there another library for TelNet that lets you do that?     tl;dr: What is the equivalent of fpsetsockopt(socket,level,TCP_NODELAY,optval, optlen) in Synapse TTelNetSend? ---------------------------------------------------------------------- VitalArt · 2016-06-17 12:38 Update:   I found this field: TTelNetSend.Sock.Socket of type TSocket which is an alias for longword. I tried passing this to fpsetsockopt in the following manner: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  TelNetClient: TTelNetSend;  f: integer;  Sock: TSocket;...  TelNetClient.Login; ...  Sock:= TelNetClient.Sock.Socket;     f:= 1;  Result:= fpsetsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, @f, Sizeof(f));   It returns zero, socketerror also returns zero, so the socket must be valid, but I see no noticable difference, the delay stays roughly the same. Also fpsetsockopt wants a longint as its sock parameter, while TTelNetSend.Sock.Socket which I pass is a longword. Maybe this is a problem? ---------------------------------------------------------------------- rvk · 2016-06-17 13:46 Quote from: VitalArt on June 17, 2016, 02:38:05 pmCode: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  f: integer;...  f:= 1;  Result:= fpsetsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, @f, Sizeof(f)); Shouldn't that integer be a boolean ?? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  NoDelay: Boolean;...  NoDelay := true;  Result:= fpsetsockopt(Sock, IPPROTO_TCP, TCP_NODELAY, @NoDelay, Sizeof(NoDelay));  (integer is 4 bytes, boolean is 1 byte) ---------------------------------------------------------------------- molly · 2016-06-17 13:56 Quote from: rvk on June 17, 2016, 03:46:01 pmShouldn't that integer be a boolean ?? (integer is 4 bytes, boolean is 1 byte) Although the latter is most certainly correct, the answer to the first would be no. See also http://www.freepascal.org/docs- html/rtl/sockets/fpsetsockopt.html which tells that optval is a pointer. Optlen determines how 'large' that optval parameter should be. A bit of clicking delivers us this page: Quotetype socklen_t = cuint32 Edit: the usual 'lenght' for this parameter for XP is integer. ---------------------------------------------------------------------- VitalArt · 2016-06-17 14:05 Okay, so I seem to have figured it out, although in a rather inelegant way. The problem was not the Nagle alghorithm which I attempted to disable, but in the so-called 'delayed ack'. https://www.linkedin.com/pulse/20141113153643-13386347-what-is- delayed-ack-and-how-can-it-be-a-bottleneck-in-your-network   I followed these instructions and created 2 registry keys in [HKEY_LOCAL_MACHINE \SYSTEM \CurrentControlSet \Services \Tcpip \Parameters \Interfaces \{Adapter-id}], DWORD TcpAckFrequency = 1, and DWORD TcpDelAckTicks = 0. At first it didn't work, but after a couple reboots and reconnecting the Ethernet cable the delay finally vanished.   So my next question is: is there a way to modify the registry (only for current connection) from within the program? Although, this isn't a nice solution either, since the delay doesn't go away until you (presumably) reconnect the cable. ---------------------------------------------------------------------- molly · 2016-06-17 14:26 Although not tested myself, maybe this SO question/answers can be of help ? Take note of the answer that claims the undocumented behaviour (again, not tested/checked and might perhaps proof impossible to use with your chosen solution). ---------------------------------------------------------------------- VitalArt · 2016-06-17 14:39 Quote from: molly on June 17, 2016, 04:26:22 pmAlthough not tested myself, maybe this SO question/answers can be of help ? I'll try it out, since I called setsockopt after connect (I thought the Socket field is only valid after the connection is established, but I guess I was wrong). However, it says there that this problem only arises on Vista or later, but in my case, on the contrary, only Windows XP is affected. ---------------------------------------------------------------------- molly · 2016-06-17 15:16 It is indeed a longshot. I was unable to find any additional (confirmative) information, let alone being able to confirm that it works for XP. It is possible to 'manipulate' socket related settings before an actual connection. I'm just not sure if it can be done for your current situation (you'd be the better judge for that :-) ) ---------------------------------------------------------------------- VitalArt · 2016-06-20 12:24 So turns out there's a variable procedure TTCPBlockSocket.OnCreateSocket which is called after bind but before connect. I used it to call fpsetsockopt in the same manner as before. Doesn't seem to work(. Well, at least the registry workaround works. I'm gonna maybe write a tool that'll create those registry entries (presumably with fcl-registry, but I haven't looked into it yet) and prompt the user to reboot the pc. Thank you for your help. ---------------------------------------------------------------------- snorkel · 2016-07-13 22:06 Nagel Algorithm enabled by chance? ---------------------------------------------------------------------- VitalArt · 2016-07-18 09:23 Quote from: snorkel on July 14, 2016, 12:06:22 amNagel Algorithm enabled by chance?   If you read through my posts carefully, you wiil find that disabling the Nagle algorhytm was exactly what I was trying to do, and found to be ineffective. However, getting rid of the 'Delayed ack' helped.