Отправка пустого ACK как части TCP-рукопожатия фактически более распространена, чем включение данных в последнюю часть TCP-рукопожатия.
Типичный код клиента сначала вызывает connect и только после успешного возврата отправляет данные. connect
вернется успешно только в том случае, если сервер ответил SYN + ACK. Ядро автоматически выдаст ACK, чтобы сообщить серверу о том, что рукопожатие завершено. Ядро не имеет данных приложения для отправки в этот момент, поэтому оно не может включить эти данные в этот ACK.
Представьте себе, что произойдет, если окончательный ACK будет отложен для ожидания большего количества потенциальных данных от клиента : в худшем случае клиент не будет отправлять такие данные, потому что он сначала ожидает данные с сервера - что типично для протоколов, таких как SMTP, FTP, .... Но так как сервер не получает ACK от клиента, он не будет считать TCP-подтверждение завершенным и, следовательно, не будет отправлять какие-либо данные. Следовательно, это приведет к ненужной задержке, пока клиент все равно не решит отправить пустой ACK.
Таким образом, чтобы оптимизировать рукопожатие, клиент должен сообщить ядру, что он немедленно начнет отправку данных и что ядро не должно уже отправлять свой ACK. По крайней мере, в Linux это можно сделать с помощью опции TCP_QUICKACK
:
import socket
s = socket.socket()
s.setsockopt(socket.IPPROTO_TCP, socket.TCP_QUICKACK, False)
s.connect(("example.com",80))
s.send(b"GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
print(s.recv(1024))
Если для TCP_QUICKACK
явно задано значение False, ACK рукопожатия TCP уже транспортирует данные приложения:
IP local-system.45664 > example.com.http: Flags [S], seq 1590101890, win 29200, options [mss 1460,sackOK,TS val 4226937632 ecr 0,nop,wscale 7], length 0
IP example.com.http > local-system.45664: Flags [S.], seq 3649111496, ack 1590101891, win 65535, options [mss 1452,sackOK,TS val 625701214 ecr 4226937632,nop,wscale 9], length 0
IP local-system.45664 > example.com.http: Flags [P.], seq 1:38, ack 1, win 229, options [nop,nop,TS val 4226937765 ecr 625701214], length 37: HTTP: GET / HTTP/1.0
Без явной настройки опции получите пустой ACK:
IP local-system.45856 > example.com.http: Flags [S], seq 4147534093, win 29200, options [mss 1460,sackOK,TS val 4227186296 ecr 0,nop,wscale 7], length 0
IP example.com.http > local-system.45856: Flags [S.], seq 123501506, ack 4147534094, win 65535, options [mss 1452,sackOK,TS val 2369778695 ecr 4227186296,nop,wscale 9], length 0
IP local-system.45856 > example.com.http: Flags [.], ack 1, win 229, options [nop,nop,TS val 4227186421 ecr 2369778695], length 0
IP local-system.45856 > example.com.http: Flags [P.], seq 1:38, ack 1, win 229, options [nop,nop,TS val 4227186421 ecr 2369778695], length 37: HTTP: GET / HTTP/1.0