Windows 上的socket API 和 Linux 的 socket API 非常相似但并不完全一样。它们都基于 BSD 套接字Berkeley Sockets模型但由于操作系统平台不同存在一些差异。功能WinsockWindowsBSD/Linux创建套接字socket()socket()绑定地址bind()bind()监听连接listen()listen()接收连接accept()accept()发送数据send()send()接收数据recv()recv()关闭连接closesocket()close()API 名称和参数基本一致所以很多网络编程代码可以在两个平台上少量修改后通用。windows上使用socket api通信时需要先初始化#ifdef _WIN32 // 存储使用winsock时初始化需要的数据 WSADATA wsa_data; // 调用WSAStartup需要传入Winsock 版本号。 WSAStartup(0x0201, wsa_data); #endif头文件功能WinsockLinux引入头文件winsock2.h、ws2tcpip.hsys/socket.h、netinet/in.h、arpa/inet.h、unistd.h 等链接库需链接 Ws2_32.lib不需要额外链接错误处理操作WinsockLinux错误码WSAGetLastError()errno错误码名称比如 WSAECONNRESET比如 ECONNRESET一个简单的阻塞tcp socket客户端程序struct sockaddr_in sin; sin.sin_family AF_INET; sin.sin_port htons(80); inet_pton(AF_INET, 142.250.71.196, sin.sin_addr); int fd socket(AF_INET, SOCK_STREAM, 0); // 选择tcp传输 if (fd 0) { std::cerr socket; return 1; } if (connect(fd, (struct sockaddr*)sin, sizeof(sin))) { std::cerr connect; closesocket(fd); return 1; } const char query[] GET / HTTP/1.0\r\n Host:www.google.com\r\n \r\n; const char* cp query; int n_written, remaining strlen(query); while (remaining 0) { n_written send(fd, cp, remaining, 0); if (n_written 0) { std::cerr send; closesocket(fd); return 1; } remaining - n_written; cp n_written; } char buf[1024]; while (1) { int result recv(fd, buf, sizeof(buf), 0); if (result 0) break; else if (result 0) { std::cerr recv; break; } fwrite(buf, 1, result, stdout); }操作系统的原生 ​​Socket API​​ 本身是​​协议无关的​​既支持 ​​TCP​​ 也支持 ​​UDP​​具体协议类型由开发者在创建 Socket 时通过参数指定。udp类型不需要connect可以直接用sendto指定ip和端口就可以直接发了一个专门表示 IPv4 地址和端口号 的结构体变量sockaddr_inhtons的作用是将 主机字节序的端口号 40713 转换为 网络字节序大端序struct sockaddr_in sin; sin.sin_port htons(40713);什么是字节序​​​​字节序​​指计算机存储​​多字节数据如16位/32位整数​​的顺序分为两种​​小端序Little-Endian​​低位字节在前常见于x86 CPU。例如40713十六进制 0x9F09在内存中存储为 09 9F低字节 0x09 在前。​​大端序Big-Endian​​高位字节在前网络标准、PowerPC等。同一数值存储为 9F 09高字节 0x9F 在前操作系统采用​​小端序Little-Endian​​主要是由于历史原因和硬件设计优化其优势体现在​​数据处理的效率​​和​​硬件设计的简化​​上。我就不复制粘贴了反正都是AI告诉我的​​TCP 粘包问题TCP 是​​面向字节流​​的协议它不保留应用层消息的边界因此会导致​​粘包Packet Sticking​​问题。​​什么是粘包​​​​粘包​​是指发送方多次调用 send() 发送的数据在接收方的一次 recv() 中全部收到导致多条消息“粘”在一起无法区分原始消息边界。​​示例​​​​发送方​​send(sockfd, Hello, 5, 0); // 发送 Hello send(sockfd, World, 5, 0); // 发送 World​​接收方​​char buf[20]; recv(sockfd, buf, sizeof(buf), 0); // 可能收到 HelloWorld粘包粘包的原因​​​​ TCP 是字节流协议​​​​不维护消息边界​​TCP 只保证数据按顺序到达不区分 send() 的调用次数。​​数据可能合并或拆分​​​​Nagle 算法​​TCP 默认会合并小数据包减少网络开销。​​内核缓冲区机制​​send() 的数据可能被拆分成多个 TCP 段或合并成一个段发送。​​接收方缓冲区读取方式​​recv() 读取的是​​当前接收缓冲区中的所有可用数据​​无法自动区分原始消息。粘包的解决方案​方法​​​​适用场景​​​​优点​​​​缺点​​​​固定长度​​简单二进制协议解析快无需转义浪费带宽​​分隔符​​文本协议如HTTP灵活人类可读需处理转义​​长度前缀​​高效二进制协议精准控制无浪费需预定义最大长度​​TCP 拆包问题TCP 拆包Packet Splitting是指发送方调用一次 send() 发送的数据可能被 TCP 协议栈拆分成多个数据包传输导致接收方需要多次 recv() 才能拼凑出完整消息。