Bind meaning
A TCP/UDP connection is typically identified by a five-tuple
{<proto>, <src addr>, <src port>, <dst addr>, <dst Port>}
Bind is usually called on the server side, bind, the address and port number of the port and the socket descriptor are bound, and the destination address and port at Connect can be determined, for the client is not required bind (but can bind), As long as the client specifies the destination address and port at Connect, the remote address and port core are automatically populated. This also explains why the server side needs bind because it requires a well-known address for the client to connect to.
So_reuseaddr
In general, the same port only allows bind once, port is not reusable, but if the port is set to reuse, it is another matter.
In bind, we can specify the address as Inaddr_any (0.0.0.0 for IPv4,: For IPv6, wildcard address), this address means all local addresses, we must select a specific address when connecting. But if a socketa bind the Inaddr_any and port P, then no other local process can use port p. But if there is a SOCKETB setting the SO_RESUEADDR option, then he can bind Port p.
So one function of option SO_RESUEADDR is to reuse the port of BIND Inaddr_any address.
Another function is to re-use the port of the TIME_WAIT state. The TIME_WAIT state has about 2, and the first is to ensure a reliable termination of TCP for full-duplex connections. Imagine the last 2 packets in the TCP disconnect, the client receives the fin sent by the server, sends an ACK, if the ACK is lost at this point, after a period of time the sever side timeout re-sends FIN, if the client is not in the TIME_WAIT state, The client sends the RST, so the connection is not terminated reliably. Its second function is to prevent old groupings from disappearing in the network. Imagine that a connection has ended, and after a while a new connection is established on the same IP address and port, if a group of the previous connection is delay in the network, then he arrives at the client side. So this state is needed to ensure that all old data is extinct.
A socket will remain in the TIME_WAIT state for 2MSL time, if you want to bind a socket to the same address and port will fail. If SO_REUSEADDR is set, you can.
So, the role of SO_REUSEADDR is:
- The port of the socket that can be reused for the address of the bind Inaddr_any.
- The address and port of the socket that can use the TIME_WAIT state.
There are 4 cases listed in the UNP, the first one is the same as the 2 above, and the 4th one is to allow full duplicate bind, but requires protocol support. The second and three types actually require a different local address for bind. In fact, we think about it, kernel is to rely on a five-tuple to differentiate a connection, even if the set reuseaddr want address reuse, but still to be able to distinguish between each other, such as the above 2 is dependent on the TCP time_wait state to differentiate, The other is that the majority of the local IP address is required to be different. On Linux, after my experiments, it is required that all sockets must be set for this flag.
So_reuseport
This option allows bind any socket to the same address and port as long as all sockets have this option set.
Linux implementations
The implementation of Linux bind is mainly in Inet_csk_get_port.
1. If the socket is set to So_resueport and the status is not listen, reuse is allowed.
bool reuse = Sk->sk_reuse && sk->sk_state! = Tcp_listen
2. If the port is 0, jump to 4, if the port is specified and not 0 (0 means that the port is automatically selected by kernel), find the port Inet_bind_bucket, if found (the port is already in use), to Tb_found. No (port not used), then to Tb_ Not_found.
Head = &HINFO->BHASH[INET_BHASHFN (NET, port, hinfo->&head->chain) if (Net_eq (Ib_net (TB), net) && Tb->port = = Port )goto tb_found; Goto TB_NOT_FOUND;JJJ
3. If not found, create a new inet_bind_bucket to reach Tb_found. In Tb_found, if the port is already in use, check whether it can be reused:
- The socket is set for forced multiplexing (sk->sk_resue = = sk_force_resue)
- The socket is set for address multiplexing (SO_REUSEADDR, reuse is true) and all users of the port are allowed address multiplexing (Tb->fastreuse > 0)
- The socket is configured for Port multiplexing (So_reuseport, Sk->sk_reuseport), and all users of the port Allow port multiplexing (Tb->fastreuseport > 0). and the valid user ID of the socket equals the valid user ID of port (uid_eq (Tb->fastid, UID))
The multiplexed port is then checked for conflicting bind_conflict.
If no one is using the port, Fastresue and Fastreuseport are set.
4. Here the kernel chooses port. Linux has made some optimizations here, such as using random selection to distribute it evenly, selecting a port from the first half of the port if Multiplexing is set, and optimizations based on parity. This part of the code is quite complex, or some places are not understood.
Bind system Call