Fundamentals 17 min read

How Does Linux Choose a Client Port for TCP Connections? Deep Dive into the Kernel

This article explains the Linux kernel's process for selecting a client-side TCP port during connect() and bind(), covering the relevant source code, random port selection algorithm, conflict checks, and common error scenarios such as "Cannot assign requested address".

Liangxu Linux
Liangxu Linux
Liangxu Linux
How Does Linux Choose a Client Port for TCP Connections? Deep Dive into the Kernel

In a TCP connection the client must pick a local port before the handshake. This article explains how Linux determines that port, both when the client calls connect() and when it explicitly calls bind().

1. Creating a socket

The client first creates a socket with socket(AF_INET, SOCK_STREAM, 0). The system call allocates several kernel objects (file, socket, sock) that are linked together. The relevant kernel source is shown.

//file: net/socket.c
SYSCALL_DEFINE3(socket, int, family, int, type, int, protocol)
{
    sock_create(family, type, protocol, &sock);
    sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK));
    ...
}

2. connect() – port selection

2.1 Call chain

When connect(fd, …) is invoked, the kernel looks up the socket object and calls sock->ops->connect, which resolves to inet_stream_connect and eventually tcp_v4_connect.

//file: net/ipv4/tcp_ipv4.c
int tcp_v4_connect(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
    tcp_set_state(sk, TCP_SYN_SENT);
    err = inet_hash_connect(&tcp_death_row, sk);   // choose a port
    err = tcp_connect(sk);                         // send SYN
}

2.2 Selecting an available port

The function inet_hash_connect forwards to __inet_hash_connect, which uses two key parameters: inet_sk_port_offset(sk) (a random offset derived from the destination address) and __inet_check_established (conflict check).

//file: net/ipv4/inet_hashtables.c
int inet_hash_connect(struct inet_timewait_death_row *death_row,
                     struct sock *sk)
{
    return __inet_hash_connect(death_row, sk,
                               inet_sk_port_offset(sk),
                               __inet_check_established,
                               __inet_hash_nolisten);
}

The algorithm reads the configured local port range ( net.ipv4.ip_local_port_range, default 32768‑61000), then iterates from a random offset, skipping reserved ports ( net.ipv4.ip_local_reserved_ports) and ports already present in the hash table hinfo->bhash. If a free port is found, it is returned; otherwise -EADDRNOTAVAIL triggers the user‑visible “Cannot assign requested address” error.

The default range provides 28 232 ports; adjust it via sysctl -w net.ipv4.ip_local_port_range="10000 60000" if needed.

2.3 When a port is already in use

If the candidate port appears in the hash table, the kernel calls check_established (implemented as __inet_check_established) to see whether an existing ESTABLISHED connection has the identical 4‑tuple. If the 4‑tuple differs (e.g., different server port), the port is still usable, allowing the same local port to serve multiple concurrent connections.

//file: net/ipv4/inet_hashtables.c
static int __inet_check_established(...){
    // iterate over ESTABLISHED sockets
    if (INET_MATCH(...)) goto not_unique;
    return 0;   // unique, can use
not_unique:
    return -EADDRNOTAVAIL;
}

2.4 Sending the SYN

After a port is chosen, tcp_connect builds a SYN packet, queues it, transmits it, and starts the retransmission timer.

//file: net/ipv4/tcp_output.c
int tcp_connect(struct sock *sk)
{
    buff = alloc_skb_fclone(MAX_TCP_HEADER + 15, sk->sk_allocation);
    tcp_init_nondata_skb(buff, tp->write_seq++, TCPHDR_SYN);
    tcp_connect_queue_skb(sk, buff);
    err = tp->fastopen_req ? tcp_send_syn_data(sk, buff)
                            : tcp_transmit_skb(sk, buff, 1, sk->sk_allocation);
    inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
                              inet_csk(sk)->icsk_rto, TCP_RTO_MAX);
}

3. bind() – explicit port selection

If the application calls bind() before connect(), the port is fixed in inet_num. Supplying a non‑zero port forces the kernel to use it; supplying 0 triggers a similar random‑range algorithm, but the conflict check only looks at sockets in the BIND state, so a port used once will not be reused by default. Using bind() on a client socket is generally discouraged because it bypasses the normal connect() selection logic.

//file: net/ipv4/af_inet.c
int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
{
    unsigned short snum = ntohs(addr->sin_port);
    if (snum && snum < PROT_SOCK && !ns_capable(...))
        goto out;
    if (sk->sk_prot->get_port(sk, snum)) {
        err = -EADDRINUSE;
        goto out_release_sock;
    }
}

4. Conclusions

The client’s local port is chosen either by connect() (random walk through ip_local_port_range) or by a prior bind(). Failure to find a free port results in “Cannot assign requested address”, often indicating an overly small ip_local_port_range. Reserved ports can be excluded via ip_local_reserved_ports. A single local port may serve multiple TCP connections as long as their 4‑tuples differ, so the practical limit on concurrent connections exceeds 65 535.

Because the selection algorithm scans the range from a random start, a nearly exhausted range can increase CPU usage of the connect() system call.

socket kernel objects
socket kernel objects
multiple connections using same client port
multiple connections using same client port
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

KernelLinuxNetworkingSocketPort Selection
Liangxu Linux
Written by

Liangxu Linux

Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.