linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Networking: L4 and above/tcp-states

kb/network-l4 ── Networking: L4 and above ── intermediate

TCP states (LISTEN, ESTABLISHED, TIME_WAIT)

A TCP session moves through 11 states from LISTEN to CLOSED. The most important in production: LISTEN, ESTABLISHED, TIME_WAIT, CLOSE_WAIT.

view as markdownaka: tcp-state, time-wait, close-wait

State machine

TCP is described by a state machine with 11 states (RFC 793). Each connection on each side is in exactly one of them at any moment. Transitions happen when SYN/ACK/FIN/RST segments are sent or received, or when timers fire.

Client and server sides

Server (passive open)         Client (active open)
CLOSED                        CLOSED
  │                             │
  │  listen()                   │  connect()
  ▼                             ▼
LISTEN                        SYN_SENT
  │                             │
  │ rcv SYN, send SYN-ACK       │  rcv SYN-ACK, send ACK
  ▼                             ▼
SYN_RECV                      ESTABLISHED
  │
  │ rcv ACK
  ▼
ESTABLISHED

Key states

  • LISTEN - the server socket is waiting for a SYN. Visible in ss -tln
  • SYN_SENT - the client sent a SYN and is waiting for a reply
  • SYN_RECV - the server received a SYN, sent a SYN-ACK, and is waiting for the ACK
  • ESTABLISHED - handshake complete; data can flow
  • FIN_WAIT_1 - we initiated the close (sent FIN)
  • FIN_WAIT_2 - the peer ACKed our FIN; we are waiting for the peer's FIN
  • CLOSE_WAIT - the peer sent FIN first and we ACKed it; your job now is to call close(). If the application does not close the socket, it stays here
  • LAST_ACK - we sent our FIN in response to CLOSE_WAIT and are waiting for the ACK
  • TIME_WAIT - both sides sent FIN+ACK; we wait 2*MSL (~60 s) to absorb any delayed packets from the old connection
  • CLOSED - no connection

TIME_WAIT: why you see so many

After a close, the active side (the one that closed first) stays in TIME_WAIT for ~60 seconds. This is by design: it protects against packets from an old connection arriving at a new one that reuses the same 4-tuple (src/dst IP+port).

On a client that opens many short-lived connections (HTTP/1.0 without keep-alive, redis clients without pooling), outgoing ports run out fast:

bash
ss -tn state time-wait | wc -l
# thousands means potential source-port exhaustion

Solutions:

  • HTTP keep-alive or connection pooling in the application
  • net.ipv4.tcp_tw_reuse=1 to reuse TIME_WAIT sockets for outgoing connect (on the client)
  • net.ipv4.ip_local_port_range to widen the ephemeral port range

CLOSE_WAIT: the application forgot close()

CLOSE_WAIT means the peer closed its side and the kernel is waiting for you to call close(). If the count grows over time, the application has a leak: it receives EOF on a socket and does not close the file descriptor. This is a classic bug in EOF handling in Node.js, Java, and Python.

Visible via ss -tn state close-wait.

§ команды

bash
ss -tn

All TCP sessions and their states

bash
ss -tnl

LISTEN sockets only (what is listening)

bash
ss -tn state time-wait | wc -l

Count of TIME_WAIT sockets; a high number signals many short-lived connections

bash
ss -tn state close-wait

Sockets in CLOSE_WAIT; the application is not calling close() on EOF

bash
ss -tnp '( dport = 443 or sport = 443 )'

What processes are connected to port 443 and from where (requires sudo for PID info)

§ см. также

  • tcp-handshakeTCP three-way handshakeTCP connection opens with three packets: SYN from the client, SYN-ACK from the server, ACK from the client. After that the connection is Established and data transfer can begin.
  • tcp-keepaliveTCP keepaliveKeepalive sends probes on an idle TCP connection to detect a dead peer (NAT timeout, crashed host). Linux defaults: 7200s idle, 75s between probes, 9 probes. Enabled via setsockopt(SO_KEEPALIVE).
  • portPort: How Multiple Services Share One IPA 16-bit number (0-65535) that identifies the **destination process** on a host. IP says which host; port says which process. 80 is HTTP, 443 is HTTPS, 22 is SSH.

§ упоминается в уроках

  • ›advanced-03-tc-netem
  • ›advanced-04-tcp-tuning
  • ›advanced-05-bandwidth-iperf
  • ›intermediate-02-tcp-handshake
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies