У меня есть TCP-сервер и несколько клиентов пытаются подключиться к этому серверу почти одновременно. Я заметил, что:
На стороне клиента connect
может возвращать 0, даже если трехстороннее рукопожатие еще не завершено.
На стороне сервера accept
может не возвращаться даже после завершения трехстороннего рукопожатия.
Чтобы проиллюстрировать обе точки, вот трассировки Wireshark (сервер прослушивает на порт 1234):
1. Вот трассировки Wireshark для случая, когда клиент connect
возвращает 0, даже если трехстороннее рукопожатие не было завершено (отсутствует последний SYN от клиента):
// calls ::connect ...
59507 → 1234 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1
1234 → 59507 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460 WS=256 SACK_PERM=1
// ... and ::connect returned 0, despite the above 2 lines
// forming an incomplete handshake. Why?
// after the ::connect, client calls ::send to send 8 bytes ...
59507 → 1234 [PSH, ACK] Seq=1 Ack=1 Win=262656 Len=8
// ... but we got reset by peer
1234 → 59507 [RST] Seq=1 Win=0 Len=0
// ... and as expected, ::send returned 10054 (WSAECONNRESET)
2 . Серверное accept
не возвращается даже после завершения трехстороннего рукопожатия:
// server calls ::accept ...
59643 → 1234 [SYN] Seq=0 Win=64240 Len=0 MSS=1460 WS=256 SACK_PERM=1
1234 → 59643 [SYN, ACK] Seq=0 Ack=1 Win=65535 Len=0 MSS=1460 WS=256 SACK_PERM=1
59643 → 1234 [ACK] Seq=1 Ack=1 Win=262656 Len=0
// At this point, we have a complete handshake, but server's ::accept doesn't return. Why?
// In the next line, server sends a RST. This doesn't cause the server's ::accept call
// to return an INVALID_SOCKET, which doesn't seem unreasonable (since nothing is accepted),
// nor is this the point of the question, but I am including the RST trace here
// for completeness. The main point is that it's as if server's ::accept is oblivious
// to the successful handshake.
1234 → 59643 [RST] Seq=1 Win=0 Len=0
Вопросы:
Когда именно возвращается connect
? Очевидно, приведенные выше трассировки предполагают, что connect
может вернуть (и объявить успех с возвращаемым значением 0), даже если рукопожатие не завершено.
Когда именно возвращается accept
? Следы выше говорят о том, что завершение трехстороннего рукопожатия недостаточно для возврата accept
, что вызывает недоумение.
Итак, это как если бы connect
не Не заботится о проверке рукопожатия, в то время как accept
настолько строг, что успешного рукопожатия недостаточно для его возврата?