Skip to content

Day45-46 - Linux Network Programming (Event-driven TCP Server)

📌 Overview

This chapter covers Linux TCP socket programming and evolves from a blocking server to a fully event-driven non-blocking server.

Key progression:

blocking → poll → epoll → non-blocking → TX queue → EPOLLOUT

📌 Socket Programming Basics

Core APIs:

socket()
bind()
listen()
accept()
recv()
send()
close()

📌 poll vs epoll

poll

  • user provides fd list every call
  • O(N) scan
  • simple but inefficient

epoll

  • kernel maintains ready list
  • scalable
  • only returns active fds

📌 Blocking vs Non-blocking

Blocking

recv() blocks until data arrives
send() blocks when buffer is full

Non-blocking

recv() → -1 (EAGAIN)
send() → -1 (EAGAIN)

📌 Event-driven Model

while (1):
    epoll_wait()
    handle events

Design rule:

  • never block inside event loop

📌 accept Queue Handling

Non-blocking accept must drain queue:

while (accept() >= 0)
    handle client

if errno == EAGAIN:
    stop

📌 recv Handling (Non-blocking)

while (1):
    recv()

    n > 0   → process
    n == 0  → client closed
    n < 0:
        EAGAIN → done
        else → error

📌 TCP is Stream (Important)

  • no message boundary
  • partial send/recv possible

📌 TX Queue Design

TX queue is NOT a packet FIFO.

Correct model:

buffer + offset

Example:

tx_buf = "hello world"
tx_len = 11
tx_off = 5
→ remaining = " world"

📌 EPOLLOUT Strategy

EPOLLOUT should NOT always be enabled.

Correct behavior:

no pending data → EPOLLIN only
pending data    → EPOLLIN | EPOLLOUT
done sending    → EPOLLIN only

📌 Why TX Queue is Needed

Because:

send() may:
- send partial data
- return EAGAIN

So remaining data must be stored.


📌 Design Principles

  • event loop must not block
  • separate RX and TX flow
  • dynamically control EPOLLOUT
  • handle partial I/O