I have a TCP server that listens for an incoming client, then sends it one packet of data every second. I was wondering, does the SYN/ACK packet only get sent on initial connection, so it looks like this:
<client connect> SYN ACK DATA DATA DATA <client disconnect>
Or does it get sent with every packet, like this?
<client connect> SYN ACK DATA SYN ACK DATA SYN ACK DATA <client disconnect>
Also, if it's the first case, are there any benefits of UDP over TCP if you just keep the connection open over a long period of time?
The host, generally the browser, sends a TCP SYNchronize packet to the server. The server receives the SYN and sends back a SYNchronize-ACKnowledgement. The host receives the server's SYN-ACK and sends an ACKnowledge. The server receives ACK and the TCP socket connection is established.
RFC 5681 mandates that an acknowledgement be sent for at least every other full-size segment, and that no more than 500ms expire before any segment is acknowledged. The resulting behavior is that, for longer transfers, acknowledgements are only sent for every two segments received ("ack every other").
Application does pass the message to TCP layer, but the operating system does not send it until an ACK from the client is received.
Therefore in case of SYN or SYN/ACK packets getting lost TCP waits 3 seconds (or longer for further back-offs) before retransmitting them. Especially for short-lived flows, this delay can significantly degrade the performance.
It's kinda like:
+-------------------------------------------------------+ | client network server | +-----------------+ +--------------------| | (connect) | ---- SYN ----> | | | | <-- SYN,ACK -- | (accepted) | | (connected) | ---- ACK ----> | | \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ when client sends... \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ | | | | | (send) | ---- data ---> | | | | <---- ACK ---- | (data received) | \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ when server sends... \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ | | | | | | <--- data ---- | (send) | | (data received) | ---- ACK ----> | | \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ ...and so on, til the connection is shut down or reset
SYN starts a connection; you'll usually only see it when the connection's being established. But all data being sent via TCP requires an ACK. Every byte sent must be accounted for, or it will be retransmitted (or the connection reset (closed), in severe cases).
Actual connections aren't usually exactly like the diagram above, though, for two reasons:
Most TCP/IP stacks try to reduce the number of naked ACKs without unduly risking retransmission or a connection reset. So a conversation like this one is quite possible:
\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/ | | | | | | <--- data ---- | (send) | | (data received) | | | | (send) | -- data,ACK -> | | | | | (data received) | | | <- data,ACK -- | (send) | | (data received) | | | | (wait a bit) | <--- data ---- | (send) | | (data received) | | | | (send) | -- data,ACK -> | | | | | (data received) | | (send) | ---- data ---> | (wait a bit) | | | | (data received) | | | <- data,ACK -- | (send) | | (data received) | | | | (wait a bit) | (dead air) | | | | ---- ACK ----> | | \_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/\_/
As for UDP, there's no built-in concept of SYN and ACK -- UDP is by nature "unreliable", and not connection-oriented, so the concepts don't apply as much. Your acknowledgement will usually just be the server's response. But some application-layer protocols built on top of UDP will have some protocol-specific way of acknowledging data sent and received.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With