:网络基石——TCP/IP 模型与 UDP 实战)
核心结论TL;DR网络通信本质是跨主机的进程间通信。靠IP Port即 Socket 套接字唯一标识网络中的进程。网络字节序网络规定使用大端字节序。发送前必须用htons/htonl转换。MAC vs IPIP 是终极目标跨网络不变MAC 是下一跳目标局域网内一直变。UDP 特性无连接、不可靠、面向数据报。UDP 开发核心服务器必须bind且 IP 选INADDR_ANY客户端不用显式bind。一、 网络基础概念计算机网络的核心目的是数据共享。为了实现不同设备、不同操作系统之间的无障碍通信采用了TCP/IP 四层或五层模型应用层、传输层、网络层、链路层。数据在发送时自上而下层层封装加报头接收时自下而上层层解包去报头。二、 核心身份标识IP、Port 与 MACIP 地址IPv4 是 32 位整数。标识互联网中唯一的主机路径选择的重要依据。端口号Port16 位整数。标识主机上的唯一进程。MAC 地址48 位。标识局域网内唯一的网卡。注意跨网络传输时IP 地址基本不变但 MAC 地址每经过一个路由器就会改变。三、 UDP 协议与核心 APIUDPUser Datagram Protocol不保证数据一定到达但速度快。socket()创建套接字。bind()绑定端口仅服务器端。sendto()发送数据。recvfrom()接收数据。四、 代码实战UDP 回显服务器struct sockaddr_in server_addr; server_addr.sin_family AF_INET; server_addr.sin_port htons(8888); // 关键INADDR_ANY 表示绑定所有本机网卡IP server_addr.sin_addr.s_addr INADDR_ANY; bind(server_fd, (struct sockaddr*)server_addr, sizeof(server_addr));五、 踩坑记录云服务器端口不通现象本地测试正常但用别的电脑连不上云服务器的 UDP 端口。原因云厂商如阿里云、腾讯云有安全组防火墙机制。解决登录云控制台在安全组入站规则中放行对应的 UDP 端口。自我实战操作cd ~/linux_study mkdir network_test cd network_test实战 1UDP 服务端UdpServervim udp_server.c(输入以下 C 语言代码最纯粹的底层逻辑)#include stdio.h #include stdlib.h #include string.h #include unistd.h #include arpa/inet.h #define PORT 8888 #define BUF_SIZE 1024 int main() { // 1. 创建 UDP 套接字 int server_fd socket(AF_INET, SOCK_DGRAM, 0); if (server_fd 0) { perror(socket); return 1; } // 2. 绑定 IP 和 端口 struct sockaddr_in server_addr; memset(server_addr, 0, sizeof(server_addr)); server_addr.sin_family AF_INET; server_addr.sin_port htons(PORT); // 端口转网络字节序 server_addr.sin_addr.s_addr INADDR_ANY; // 监听任意IP超级重要 if (bind(server_fd, (struct sockaddr*)server_addr, sizeof(server_addr)) 0) { perror(bind); return 1; } printf(UDP 服务器已启动监听端口 %d...\n, PORT); // 3. 循环接收和发送 char buffer[BUF_SIZE]; struct sockaddr_in client_addr; socklen_t client_len sizeof(client_addr); while (1) { // 接收客户端发来的数据 int n recvfrom(server_fd, buffer, BUF_SIZE - 1, 0, (struct sockaddr*)client_addr, client_len); if (n 0) { buffer[n] \0; printf(收到来自 %s:%d 的消息: %s\n, inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port), buffer); // Echo (原样发回) sendto(server_fd, buffer, n, 0, (struct sockaddr*)client_addr, client_len); } } close(server_fd); return 0; }实战 2UDP 客户端UdpClientvim udp_client.c(输入以下代码)#include stdio.h #include stdlib.h #include string.h #include unistd.h #include arpa/inet.h #define SERVER_IP 127.0.0.1 // 本地测试 #define PORT 8888 #define BUF_SIZE 1024 int main() { // 1. 创建 UDP 套接字 (不需要显式 bind系统会自动分配随机端口) int client_fd socket(AF_INET, SOCK_DGRAM, 0); if (client_fd 0) { perror(socket); return 1; } // 2. 配置服务器地址信息 struct sockaddr_in server_addr; memset(server_addr, 0, sizeof(server_addr)); server_addr.sin_family AF_INET; server_addr.sin_port htons(PORT); inet_pton(AF_INET, SERVER_IP, server_addr.sin_addr); // 字符串IP转二进制 char buffer[BUF_SIZE]; while (1) { printf(请输入要发送的消息 (输入 quit 退出): ); fgets(buffer, BUF_SIZE, stdin); buffer[strcspn(buffer, \n)] 0; // 去掉换行符 if (strcmp(buffer, quit) 0) break; // 发送数据 sendto(client_fd, buffer, strlen(buffer), 0, (struct sockaddr*)server_addr, sizeof(server_addr)); // 接收回显数据 struct sockaddr_in temp_addr; socklen_t temp_len sizeof(temp_addr); int n recvfrom(client_fd, buffer, BUF_SIZE - 1, 0, (struct sockaddr*)temp_addr, temp_len); if (n 0) { buffer[n] \0; printf(收到服务器回显: %s\n, buffer); } } close(client_fd); return 0; }实战 3编译测试与网络排错# 编译 gcc udp_server.c -o udp_server gcc udp_client.c -o udp_client测试流程开终端 A服务端./udp_server开终端 B客户端./udp_client在终端 B 输入hello看看终端 A 和 B 分别打印了什么。排错加餐如果你把服务端跑在云服务器上客户端在自己的电脑上Windows你必须在云服务器后台的安全组里开放8888的UDP 端口否则数据会被防火墙拦截