
1. 套接字基础概念解析套接字Socket是网络编程中最基础也是最重要的概念之一。简单来说套接字就是网络通信的端点就像我们打电话时需要电话号码一样网络中的进程通信需要套接字来标识通信的双方。在实际开发中套接字可以理解为网络通信的插座。想象一下你的电脑是一个房间套接字就是墙上安装的插座通过这个插座你可以连接各种电器网络服务。每个插座都有特定的规格协议类型和位置IP地址端口号。套接字的核心组成要素包括IP地址标识网络中的主机端口号标识主机上的特定进程协议类型决定通信方式TCP/UDP注意在Linux系统中套接字本质上是一个文件描述符file descriptor这意味着你可以像操作普通文件一样操作套接字使用read/write等系统调用。2. TCP与UDP协议深度对比2.1 协议特性对比表特性TCPUDP连接方式面向连接三次握手无连接可靠性可靠传输确认、重传机制尽力而为交付数据顺序保证数据顺序不保证顺序流量控制滑动窗口机制无控制传输效率相对较低较高头部大小20-60字节8字节适用场景文件传输、网页浏览视频流、DNS查询2.2 TCP的可靠性实现机制TCP之所以被称为可靠协议是因为它实现了以下机制序列号和确认应答每个数据包都有唯一序列号接收方需要发送ACK确认超时重传未收到ACK时会重发数据流量控制通过滑动窗口动态调整发送速率拥塞控制慢启动、拥塞避免等算法防止网络过载2.3 UDP的高效性特点UDP的优势在于其简洁性无连接无需建立和断开连接的开销无状态服务端不需要维护连接状态小头部仅8字节头部远小于TCP无控制机制不进行流量和拥塞控制实际经验在局域网等可靠网络中UDP的性能优势更加明显。我曾在一个内网视频监控项目中使用UDP协议将传输延迟从TCP的200ms降低到了50ms以下。3. 核心结构体详解3.1 通用地址结构体sockaddrstruct sockaddr { unsigned short sa_family; // 地址族 char sa_data[14]; // 地址数据 };这个结构体是各种具体地址结构体的基类实际编程中我们通常使用更具体的派生结构体。3.2 IPv4专用结构体sockaddr_instruct sockaddr_in { short sin_family; // 地址族(AF_INET) unsigned short sin_port; // 端口号(网络字节序) struct in_addr sin_addr; // IPv4地址 char sin_zero[8]; // 填充字段 }; struct in_addr { unsigned long s_addr; // IPv4地址(网络字节序) };3.3 字节序转换函数网络编程中必须注意字节序问题常用转换函数包括htons()主机到网络短整型(端口号)htonl()主机到网络长整型(IP地址)ntohs()网络到主机短整型ntohl()网络到主机长整型避坑指南我曾遇到过因为忘记转换字节序导致服务无法连接的bug。建议在代码中添加明确的注释如serv_addr.sin_port htons(8080); // 必须转换为网络字节序4. UDP编程实战4.1 UDP服务端实现步骤创建套接字int sockfd socket(AF_INET, SOCK_DGRAM, 0);绑定地址struct sockaddr_in serv_addr; memset(serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family AF_INET; serv_addr.sin_addr.s_addr htonl(INADDR_ANY); // 监听所有网卡 serv_addr.sin_port htons(PORT); // 设置端口 bind(sockfd, (struct sockaddr*)serv_addr, sizeof(serv_addr));接收/发送数据struct sockaddr_in cli_addr; socklen_t len sizeof(cli_addr); while(1) { char buffer[1024]; int n recvfrom(sockfd, buffer, sizeof(buffer), 0, (struct sockaddr*)cli_addr, len); // 处理数据并回复 sendto(sockfd, Response, 8, 0, (struct sockaddr*)cli_addr, len); }4.2 UDP客户端实现步骤创建套接字int sockfd socket(AF_INET, SOCK_DGRAM, 0);设置服务端地址struct sockaddr_in serv_addr; memset(serv_addr, 0, sizeof(serv_addr)); serv_addr.sin_family AF_INET; serv_addr.sin_addr.s_addr inet_addr(192.168.1.100); serv_addr.sin_port htons(PORT);发送数据sendto(sockfd, Hello, 5, 0, (struct sockaddr*)serv_addr, sizeof(serv_addr));4.3 UDP编程注意事项数据边界UDP保留数据报边界一次sendto对应一次recvfrom最大数据量单个UDP数据报最好不超过1472字节(以太网MTU1500-IP头20-UDP头8)错误处理UDP不保证送达应用层需要自己实现超时重传多线程安全UDP套接字是线程安全的可以多线程同时操作5. TCP编程实战5.1 TCP服务端实现步骤创建监听套接字int listen_fd socket(AF_INET, SOCK_STREAM, 0);绑定地址struct sockaddr_in serv_addr; // ...初始化地址... bind(listen_fd, (struct sockaddr*)serv_addr, sizeof(serv_addr));开始监听listen(listen_fd, 5); // 第二个参数是等待队列长度接受连接struct sockaddr_in cli_addr; socklen_t len sizeof(cli_addr); int conn_fd accept(listen_fd, (struct sockaddr*)cli_addr, len);通信循环while(1) { int n recv(conn_fd, buffer, sizeof(buffer), 0); if(n 0) break; // 连接关闭或出错 // 处理数据 send(conn_fd, response, strlen(response), 0); }5.2 TCP客户端实现步骤创建套接字int sockfd socket(AF_INET, SOCK_STREAM, 0);连接服务器struct sockaddr_in serv_addr; // ...初始化服务器地址... connect(sockfd, (struct sockaddr*)serv_addr, sizeof(serv_addr));发送/接收数据send(sockfd, Hello, 5, 0); recv(sockfd, buffer, sizeof(buffer), 0);5.3 TCP编程注意事项粘包问题TCP是流式协议需要应用层处理消息边界连接管理正确处理连接断开和重连阻塞模式默认是阻塞IO考虑使用select/poll/epoll处理多连接缓冲区大小适当设置SO_SNDBUF和SO_RCVBUF参数6. 高级话题与性能优化6.1 IO多路复用技术对于高并发服务器常见的IO模型包括select跨平台支持好但性能有限poll解决了select的一些限制epollLinux特有性能最高示例epoll使用int epfd epoll_create1(0); struct epoll_event ev, events[MAX_EVENTS]; ev.events EPOLLIN; ev.data.fd sockfd; epoll_ctl(epfd, EPOLL_CTL_ADD, sockfd, ev); while(1) { int nfds epoll_wait(epfd, events, MAX_EVENTS, -1); for(int i 0; i nfds; i) { if(events[i].data.fd sockfd) { // 处理新连接 } else { // 处理数据 } } }6.2 常见性能优化手段设置套接字选项int opt 1; setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, opt, sizeof(opt));调整缓冲区大小int buf_size 1024 * 1024; setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, buf_size, sizeof(buf_size));使用非阻塞IOfcntl(sockfd, F_SETFL, O_NONBLOCK);批量发送数据减少系统调用次数7. 实战经验与排错指南7.1 常见错误代码及处理错误代码含义解决方法EADDRINUSE地址已被使用设置SO_REUSEADDR选项ECONNREFUSED连接被拒绝检查目标服务是否运行ETIMEDOUT连接超时检查网络连通性ENOBUFS缓冲区不足增大系统网络缓冲区7.2 网络调试工具tcpdump抓包分析工具tcpdump -i eth0 port 8080 -nn -vvnetstat查看网络状态netstat -tulnpnc网络瑞士军刀nc -l 8080 # 启动简易服务器 nc localhost 8080 # 连接服务器7.3 性能测试工具iperf网络带宽测试# 服务端 iperf -s # 客户端 iperf -c server_ipabHTTP压力测试ab -n 1000 -c 100 http://localhost:8080/在实际项目开发中我总结出几个关键点第一网络编程中90%的问题都可以通过抓包分析解决第二TCP的性能调优需要结合具体应用场景第三良好的错误处理和日志记录能极大提高调试效率。