Windows需调用WSAStartup初始化Winsock并用WSACleanup清理,Linux无需;socket关闭须用closesocket(Windows)或close(Linux),读写应统一用recv/send;错误码获取需分平台用WSAGetLastError或errno,头文件包含顺序及地址解析也需跨平台适配。

Windows和Linux的Socket初始化差异在哪
Windows必须显式调用 WSAStartup 初始化Winsock库,否则所有Socket函数(如 socket、connect)都会失败并返回错误码 WSANOTINITIALISED;Linux则完全不需要这一步。这是跨平台Socket代码第一个必须处理的分歧点。
常见错误是只在Windows下写了初始化,但忘了在程序退出前调用 WSACleanup,导致资源泄漏;或者在Linux下误加了这两句,引发编译错误(WSAStartup 未声明)。
实操建议:
- 用
#ifdef _WIN32包裹初始化与清理逻辑,#else分支留空 -
WSAStartup的第二个参数必须传入有效指针(如WSADATA变量),不能为nullptr - 检查
WSAStartup返回值:非零即失败,不要只看是否为0 - Linux下无需任何前置操作,直接调用
socket即可
socket()、closesocket() 和 close() 的兼容写法
Windows用 closesocket 关闭套接字,Linux用 close;混用会导致编译失败或运行时崩溃(比如在Windows上调用 close 可能不报错但实际没释放句柄)。
立即学习“C++免费学习笔记(深入)”;
更隐蔽的问题是:Linux下 socket 返回的是文件描述符(int),而Windows下虽然是int类型,但语义上不是fd——所以不能直接传给 read/write,必须用 recv/send;Linux两者都支持,但用 recv/send 更一致。
实操建议:
- 统一用宏定义封装关闭操作:
#ifdef _WIN32→#define CLOSE_SOCKET closesocket,否则 →#define CLOSE_SOCKET close - 读写一律使用
recv/send(而非read/write),避免Windows下行为异常 - 注意
send在TCP中可能只发出部分数据,需循环处理返回值,这点Windows/Linux一致 - Linux下
socket错误返回-1,Windows下返回INVALID_SOCKET(即-1),可统一判断== -1,但语义上建议用== INVALID_SOCKET并仅在Windows下定义该宏
errno 和 WSAGetLastError 的错误码映射问题
Linux通过全局变量 errno 获取错误,Windows必须调用 WSAGetLastError;两者错误码数值不同(如连接被拒:Linux是 ECONNREFUSED(111),Windows是 WSAECONNREFUSED(10061)),直接比较数字会失效。
如果封装了统一的错误处理函数,却忘了按平台分支取错,就可能出现“明明连不上,却打印出‘Success’”这类诡异现象。
实操建议:
- 定义统一错误码获取宏:
#ifdef _WIN32→#define GET_SOCKET_ERR() WSAGetLastError(),否则 →#define GET_SOCKET_ERR() errno - 不要直接把
GET_SOCKET_ERR()值和某个平台常量比较,应封装转换函数或用 switch 分平台判断 - 调试时打印错误码原始值(
printf("err=%d", GET_SOCKET_ERR()))比依赖字符串描述更可靠 - 注意:某些函数(如
getaddrinfo)自己管理错误码,不走errno或WSAGetLastError,需单独处理
struct sockaddr_storage 和头文件包含顺序
Linux下 sockaddr_storage 在 中定义,Windows需包含 <>winsock2.h>(且必须在 之前),否则可能因宏冲突导致编译失败。更麻烦的是:MSVC默认可能隐式包含旧版 winsock.h,与 winsock2.h 冲突。
另一个坑是:Windows下 in_addr、sockaddr_in 等结构体字段名与Linux基本一致,但大小端、填充对齐等底层细节仍可能影响二进制兼容性(尤其做序列化时)。
实操建议:
- Windows平台强制先
#include,再#include;Linux下按常规顺序包含、、 - 避免直接包含
,如必须,加#define WIN32_LEAN_AND_MEAN并确保它在winsock2.h之前 - 地址解析统一用
getaddrinfo(POSIX/Windows均支持),别手写inet_addr+htons组合 - 跨平台传递地址结构时,始终用
sockaddr_storage存储,用getnameinfo提取IP/端口字符串,避免字段直读
最难缠的往往不是功能实现,而是那些只在某个平台触发的隐式依赖——比如忘了在Windows下初始化Winsock,或Linux下误用了Windows专属宏。每次新增网络功能,最好立刻在两个平台各跑一遍基础连接测试,而不是等集成时才发现 socket 返回 -1 却查不出原因。










