必须先调用WSAStartup初始化Winsock,否则socket()返回INVALID_SOCKET且WSAGetLastError()返回10093(WSANOTINITIALISED);需传入正确版本号(如MAKEWORD(2,2))、检查返回值是否为0,并在程序退出前调用WSACleanup()。

Windows下用WSAStartup初始化失败怎么办
直接调socket()会返回INVALID_SOCKET,因为Windows的Socket API必须先初始化。不调WSAStartup就用网络函数,基本等于没插网线还按开机键。
常见错误是传错版本号或忽略返回值:
-
WSAStartup(MAKEWORD(2,2), &wsaData)才支持IPv6和较新特性;用MAKEWORD(1,1)可能在Win10+上被拒绝 - 必须检查返回值是否为0,非零说明初始化失败,此时
WSAGetLastError()能拿到具体错误码(比如WSASYSNOTREADY) - 程序退出前得调
WSACleanup(),否则资源泄漏,多次运行后可能触发WSAStartup失败
创建TCP客户端时connect()一直超时
不是代码写错了,大概率是目标地址/端口不通,或防火墙拦了。别急着改SOCKET选项,先做三件事:
- 用
ping确认IP可达(注意:有些服务器禁ping,但不影响TCP) - 用
telnet 127.0.0.1 8080或nc -zv 127.0.0.1 8080验证端口是否监听——如果连不上,问题出在服务端或本地防火墙 -
connect()返回SOCKET_ERROR时,立刻查WSAGetLastError():WSAECONNREFUSED说明服务没起来,WSAETIMEDOUT才是真网络问题
别忘了设置sockaddr_in里的sin_family = AF_INET、sin_port = htons(8080),字节序和协议族错一个,connect()直接失败且错误码不直观。
立即学习“C++免费学习笔记(深入)”;
用send()发数据却只发出一部分
send()不保证一次把缓冲区全发完,尤其在非阻塞模式或网络拥塞时。返回值是“实际发送字节数”,可能小于你传入的长度。
- 必须用循环重发剩余部分,例如:
int sent = 0; while (sent - 阻塞模式下也可能只发一部分——别假设
send()等价于“写入完成” - 如果想避免手动循环,可设
SOCK_STREAMsocket的SO_SNDBUF(但治标不治本,底层仍是分片)
Linux和Windows的Socket头文件与清理方式差异
跨平台写法容易翻车。核心区别就三点:
- 头文件:
#include <sys/socket.h>+<netinet/in.h>+<arpa/inet.h>(Linux),Windows用#include <winsock2.h> - 关闭socket:
close(sock)(Linux),closesocket(sock)(Windows)——混用会崩溃 - 错误码:
errno(Linux),WSAGetLastError()(Windows),不能统一用strerror(errno)
如果硬要写一份代码跑两边,得用#ifdef _WIN32切逻辑,但更稳妥的做法是封装一层net_close()、net_last_error(),把差异锁死在几个函数里。不然每次改一行,编译器报十行错。


















