Project

General

Profile

Feature #11507

Net::HTTP should use TCP_CORK or TCP_NOPUSH to avoid fragmenting packets

Added by canatella (Damien Merenne) about 4 years ago.

Status:
Open
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:<unknown>]

Description

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.

Also available in: Atom PDF