[ruby-core:70661] [Ruby trunk - Feature #11507] [Open] Net::HTTP should use TCP_CORK or TCP_NOPUSH to avoid fragmenting packets

From: dam@...
Date: 2015-09-04 09:47:26 UTC
List: ruby-core #70661
Issue #11507 has been reported by Damien Merenne.

----------------------------------------
Feature #11507: Net::HTTP should use TCP_CORK or TCP_NOPUSH to avoid fragmenting packets
https://bugs.ruby-lang.org/issues/11507

* Author: Damien Merenne
* Status: Open
* Priority: Normal
* Assignee: 
----------------------------------------
I discovered while implementing a soap client against a badly implemented http server that for sending a 723 bytes, Net::HTTP sends two packets:

~~~
Frame 185: 579 bytes on wire (4632 bits), 579 bytes captured (4632 bits) on interface 0
Point-to-Point Protocol
Internet Protocol Version 4, Src: 127.0.0.1 (127.0.0.1), Dst: 127.0.0.1 (127.0.0.1)
Transmission Control Protocol, Src Port: 63525 (63525), Dst Port: 7001 (7001), Seq: 210, Ack: 1, Len: 523
[2 Reassembled TCP Segments (732 bytes): #183(209), #185(523)]
    [Frame: 183, payload: 0-208 (209 bytes)]
    [Frame: 185, payload: 209-731 (523 bytes)]
    [Segment count: 2]
    [Reassembled TCP length: 732]
    [Reassembled TCP Data: 504f5354202f20485454502f312e310d0a534f4150416374...]
Hypertext Transfer Protocol
    POST / HTTP/1.1\r\n
    SOAPAction: ""\r\n
    Content-Type: text/xml;charset=UTF-8\r\n
    Content-Length: 523\r\n
    Accept-Encoding: gzip;q=1.0,deflate;q=0.6,identity;q=0.3\r\n
    Accept: */*\r\n
    User-Agent: Ruby\r\n
    Host: 172.16.129.10:7001\r\n
    \r\n
    [Full request URI: http://127.0.0.1:7001/]
    [HTTP request 1/1]
    [Response in frame: 187]
eXtensible Markup Language
~~~

So Net::HTTP client performance could be improved by using the TCP_CORK option on Linux and TCP_NOPUSH option on BSD's.

I implemented at the time an embedded tcp server on a relatively slow MIPS processor under Linux and using TCP_CORK greatly improved the throughput of the server, so it might also help here. I suppose it also depends on the network hardware.

Implementing this simply means (on linux at least) calling 
~~~
int state = 1;
setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
~~~
before starting to write the request and
~~~
int state = 0;
setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state));
~~~
after when it's written. It will prevent the kernel to send anything until the request is completely written. From what I see, the BasicSocket::setsockopt supports TCP_CORK so that should be quite easy. Unfortunatly I do not have time to implement that right now but I hope I'll be able to implement it and do some tests soon.




-- 
https://bugs.ruby-lang.org/

In This Thread

Prev Next