知识全景图/ 软件工程与系统/ 如何设计系统/ 如何设计操作系统/ 网络与 Socket

如何设计网络与 Socket

把网卡收到的包变成用户程序可读写、可阻塞、可限额的 fd。

定位:这页不实现完整 TCP/IP。它只讲 ToyOS 第一版网络接口:应用不直接碰网卡,而是通过 socket fd 收发字节流或数据报。
一、坏场景:网络包到了,但用户程序不该直接碰网卡
失败:网卡中断带来数据包。如果用户程序直接读网卡队列,就会绕过端口权限、破坏其他连接、抢占缓冲区。网络必须先进入内核协议和 socket 账本。
问题直接做会怎样坏被迫设计
包属于哪个程序应用自己抢包,端口归属混乱端口表、socket 表
到达速度和读取速度不同包丢失或无限占内存接收缓冲区和背压
连接有状态应用自己处理状态,错误不可控socket state machine
网络也是 fdread/write/poll 无法统一socket fd 接入文件表
二、最小 socket 对象
对象字段负责什么
Socketstate、local_addr、remote_addr、rx_buffer、tx_buffer一条网络端点的状态和缓冲
PortTableport → socket把到达端口的数据交给对应 socket
Packetsrc、dst、payload、protocol内核处理的网络数据单元
AcceptQueuepending_connections保存等待 accept 的连接
NetworkBufferdata、len、capacity、limit吸收网卡和应用速度差
三、最小系统调用
系统调用职责必须检查
socket()创建 socket 对象并返回 fdfd 上限、内存上限
bind(fd, addr)绑定本地地址和端口端口是否被占用,是否有权限
listen(fd)进入监听状态socket 状态是否正确
accept(fd)取出一个待处理连接队列为空时阻塞或返回错误
connect(fd, addr)主动连接远端地址合法、路由可达、状态转换合法
read/write收发 socket 数据缓冲区、连接状态、用户指针
四、收包路径
network_interrupt: packet = nic.read_packet() socket = port_table.lookup(packet.dst_port) if socket == null: drop(packet) else if socket.rx_buffer.full: apply_backpressure_or_drop(packet) else: socket.rx_buffer.push(packet.payload) wakeup(socket.read_wait_queue)
阶段内核动作失败处理
网卡中断驱动取包坏包丢弃
协议解析识别目标地址、端口、协议未知协议丢弃或返回错误
路由到 socket查端口表和连接表无监听者丢弃或拒绝
进入缓冲区放入 rx_buffer满了就背压或丢弃
唤醒进程read 阻塞者变 ready唤醒条件必须精确
五、验收实验
实验通过标准证明了什么
监听实验服务进程 bind/listen 后,端口表可查端口归属成立
连接实验客户端 connect 后,服务端 accept 返回新 fd连接状态机成立
收包实验网卡包进入对应 socket rx_buffer中断到 socket 路径成立
阻塞实验rx_buffer 空时 read 阻塞,数据到达后唤醒网络和调度器联动成立
限额实验连接数或缓冲区超过上限时返回错误或丢弃网络不能无限吃内存
六、回到操作系统主线
下一页:资源限制与故障恢复
网络、文件和进程都有上限。继续看 如何设计资源限制与故障恢复
回总页
一句话:socket 的价值不是“能联网”,而是把网络连接收成一个受权限、缓冲、状态机和调度器管理的 fd。