An implementation is required to support the maximum-sized TCP and IP headers, which are 60 bytes each.
An implementation must support 576-byte datagrams, which even with maximum-headers means more than 8 bytes of data in the datagram. To send datagrams with more than 8 bytes of data, IP fragmentation must put at least 8 bytes of data in at least one of the packets that represent the fragments of the datagram. Thus an implementation must support at least 8 bytes of data in a packet.
Putting this together, an implementation must support 60+60+8 byte packets.
When we send packets that are part of a TCP stream, they have a 20-byte IP header (plus options) and a 20-byte TCP header (plus options). That leaves a minimum of (60+60+8)-(20+20) bytes remaining for data and options. Hence this is the maximum we can safely assume an implementation's TCP MSS.
It's part of the TCP (or UDP, etc.) header, in the packet. So the server finds out because the client tells it. This is similar to how it finds out the client's IP address (which is part of the IP header).
E.g., every TCP packet includes an IP header (with source IP, destination IP, and protocol [TCP], at least). Then there is a TCP header (with source and destination port, plus more).
When the kernel receives a SYN packet (the start of a TCP connection) with a remote IP of 10.11.12.13 (in the IP header) and a remote port of 12345 (in the TCP header), it then knows the remote IP and port. It sends back a SYN|ACK. If it gets an ACK back, the listen
call returns a new socket, set up for that connection.
A TCP socket is uniquely identified by the four values (remote IP, local IP, remote port, local port). You can have multiple connections/sockets, as long as at least one of those differs.
Typically, the local port and local IP will be the same for all connections to a server process (e.g. all connections to sshd will be on local-ip:22). If one remote machine makes multiple connections, each one will use a different remote port. So everything but the remote port will be the same, but that's fine—only one of the four has to differ.
You can use, e.g., wirehsark to see the packet, and it'll label all the data for you. Here is the source port highlighted (notice it highlighted in the decoded packet, as well as the hex dump at the bottom):
Best Answer
Just to make sure we're on the same page (your question is ambiguous this way), asking to bind TCP on port 0 indicates a request to dynamically generate an unused port number. In other words, the port number you're actually listening on after that request is not zero. There's a comment about this in
[linux kernel source]/net/ipv4/inet_connection_sock.c
oninet_csk_get_port()
:Which is a standard unix convention. There could be systems that will actually allow use of port 0, but that would be considered a bad practice. This behaviour is not officially specified by POSIX, IANA, or the TCP protocol, however.1 You may find this interesting.
That's why you cannot sensibly make a TCP connection to port zero. Presumably
nc
is aware of this and informs you you're making a non-sensical request. If you try this in native code:You get the same error you would trying to connect to any other unavailable port:
ECONNREFUSED
, "Connection refused". So in reply to:Probably not; it doesn't require special handling. I.e., if you can find a system that allows binding and listening on port 0, you could presumably connect to it.
1. But IANA does refer to it as "Reserved" (see here). Meaning, this port should not be used online. That makes it okay with regard to the dynamic assignment convention (since it won't actually be used). Stipulating that specifically as a purpose would probably be beyond the scope of IANA; in essence operating systems are free to do what they want with it, including nothing.