从零写OS(四十五):TCP 服务端——bind/listen/accept

前面几章都是做 TCP 客户端——发 SYN、连接、发请求、收响应。这章反过来,让内核能作为 TCP 服务端:监听端口,接受连接,响应请求。 客户端 vs 服务端的区别 客户端:主动发 SYN,等待 SYN-ACK。 服务端:被动等待 SYN,收到后发 SYN-ACK,等 ACK 完成三次握手,然后通过 accept() 把新连接交给应用层。 关键区别在于:服务端有两种 socket 角色—— 角色 职责 监听 socket(listen fd) 绑定端口,等待连接请求 连接 socket(accept fd) 每个客户端连接对应一个,负责实际数据收发 三步接口 bind(fd, &sa, len) // 绑定本地端口 listen(fd, backlog) // 进入监听状态 accept(fd, &sa, &len) // 阻塞,等到有连接,返回新 fd 数据结构 tcp_sock_t 加了几个字段: int is_listener; int accept_queue[8]; // 存已完成三次握手的连接 index uint32_t accept_head, accept_tail; 还新增了两个状态: TCP_LISTEN:监听中,等待 SYN TCP_SYN_RECV:收到 SYN 已回 SYN-ACK,等最终 ACK 核心流程 1. 收到 SYN tcp_handle() 里单独处理 SYN: if ((tcp->flags & TCP_SYN) && !(tcp->flags & TCP_ACK)) { // 找到监听该端口的 socket // 分配新连接 slot ns->state = TCP_SYN_RECV; ns->local_port = dport; ns->remote_port = sport; ns->remote_ip = src_ip; ns->ack = ntohl(tcp->seq) + 1; // 下次要 ACK 的序号 ns->syn_seq = 0xABCD1234; ns->snd_una = ns->snd_nxt = ns->syn_seq; tcp_send_seg(ns, ns->syn_seq, TCP_SYN | TCP_ACK, 0, 0); } 2. 收到最终 ACK(完成三次握手) if (s->state == TCP_SYN_RECV && (tcp->flags & TCP_ACK)) { if (ack_val == s->syn_seq + 1) { s->snd_una = s->snd_nxt = ack_val; s->state = TCP_ESTABLISHED; // 放入监听 socket 的 accept queue ls->accept_queue[ls->accept_tail % 8] = i; ls->accept_tail++; } } 3. accept() 取连接 int tcp_accept(int s, ...) { tcp_sock_t *ls = &tcp_socks[s]; while (ls->accept_head == ls->accept_tail) { sti; net_poll(); cli; // 阻塞等待 } int ni = ls->accept_queue[ls->accept_head++ % 8]; return ni; } 测试 写了一个简单的 HTTP 服务端程序: ...

June 2, 2026 · 2 min · 大飞
京ICP备14031575号-3