《CSAPP》11

发布时间:2026/5/20 5:38:03

《CSAPP》11 客户端-服务器模型角色分离的计算架构通信双方分为服务端和客户端。服务端持续运行、监听特定端口等待客户端请求。客户端按需发起连接、发送请求、接收响应后终止。模型通信的基本操作是“事务”指客户端与服务器之间一次完整、原子的请求-响应交互过程。原子性:事务要么成功请求送达响应返回要么失败超时/连接中断。中间状态对应用层不可见。网络[应用层] Hello ↓ HTTP头若Web请求 [传输层] TCP段 [源端口:54321 | 目的端口:80 | 序号 | 确认号 | ... | Hello] ↓ TCP头部20字节 [网络层] IP数据报 [源IP:192.168.1.10 | 目的IP:203.0.113.5 | TTL | ... | TCP段] ↓ IP头部20字节 [链路层] 以太网帧 [源MAC | 目的MAC | 类型 | IP数据报 | CRC] ↓ 帧头部14字节 尾部4字节 [物理层] 01010101...电信号/光信号-经过路由器转发-服务器网卡接收-逆向解封装-应用层read()得到Hello。代码运行在主机上主机拥有IP和端口用来定位服务发出去的信息经过路由器链路交换机等设备到达目的主机。进行通信服务。IP因特网IP标识主机与端口协同定位。struct in_addr { uint32_t s_addr; // 网络字节序大端存储 };套接字接口套接字socket是I/O思想的延申。特性普通文件套接字CSAPP深意抽象int fd open(...)int sockfd socket(...)统一I/O模型所有I/O通过fd操作读写read(fd, buf, n)read(sockfd, buf, n)程序员无需区分数据来源关闭close(fd)close(sockfd)资源管理模型完全一致内核视角文件表项 → inode套接字表项 → 协议控制块Everything is a file#include sys/socket.h int socket(int domain, int type, int protocol);domin:可选AF_INET(ipv4)\AF_INET6(ipv6)\AF_UNIX(本地)type:可选SOCK_STREAM(TCP)\SOCK_DGRAM(UDP)\SOCK_SEQPACKETprotocal:首选为0可选IPPROTO_TCP\IPPROTO_UDP套接字地址结构#include netinet/in.h struct sockaddr_in { sa_family_t sin_family; // 2字节必须为AF_INET in_port_t sin_port; // 2字节**网络字节序**端口号 struct in_addr sin_addr; // 4字节**网络字节序**IPv4地址 char sin_zero[8]; // 8字节填充至sockaddr大小必须清零 };socket(协议栈出生证明)#include sys/socket.h int socket(int domain, int type, int protocol);参数可选值CSAPP推荐内核行为domainAF_INET(IPv4)AF_INET6(IPv6)AF_UNIX(本地)AF_INET创建对应协议族的套接字控制块PCBtypeSOCK_STREAM(TCP)SOCK_DGRAM(UDP)SOCK_STREAM初始化传输层状态机TCP: CLOSED → LISTEN/SYN_SENTprotocol0(自动)IPPROTO_TCPIPPROTO_UDP0由domaintype推导协议号TCP6, UDP17bind 绑定本地地址#include sys/socket.h int bind(int sockfd, const struct sockaddr *addr, socklen_t addrlen);sockfdsocket返回的fd必须是未连接的套接字TCP处于CLOSED状态addr指向协议特定地址结构必须经getaddrinfo填充或手动初始化字节序转换addrlen地址结构实际大小sizeof(struct sockaddr_in)非sizeof(sockaddr)listen 转换为被动套接字#include sys/socket.h int listen(int sockfd, int backlog);sockfd已bind的套接字状态从CLOSED → LISTENTCP三次握手起点backlog连接请求队列长度非精确值实际 min(backlog, /proc/sys/net/core/somaxconn)accept 提取连接#include sys/socket.h int accept(int listenfd, struct sockaddr *addr, // 输出客户端地址 socklen_t *addrlen); // 输入/输出地址长度connect 客户端连接#include sys/socket.h int connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen);参数说明CSAPP关键点sockfd客户端套接字socket创建状态CLOSED → SYN_SENTaddr服务器地址经getaddrinfo解析必须包含有效IP端口addrlen地址结构大小res-ai_addrlen来自getaddrinfo主机和服务的转换人类视角机器视角转换必要性www.csapp.org128.2.194.242域名需解析为IP网络层寻址http或800x0050网络字节序服务名/端口号需转为二进制端口传输层多路分解localhost127.0.0.1本地测试需映射回环地址int getaddrinfo( const char *node, // 主机名或IP字符串NULL本机 const char *service, // 服务名(http)或端口号(80) const struct addrinfo *hints, // 指导解析关键 struct addrinfo **res // 输出地址链表头指针 ); struct addrinfo { int ai_flags; // AI_PASSIVE, AI_CANONNAME... int ai_family; // AF_INET, AF_INET6, AF_UNSPEC int ai_socktype; // SOCK_STREAM, SOCK_DGRAM int ai_protocol; // 0自动 socklen_t ai_addrlen; // 输出地址结构大小 struct sockaddr *ai_addr; // 输出地址结构指针 char *ai_canonname; // 输出规范主机名 struct addrinfo *ai_next; // 链表指针 };

相关新闻