从Winsock开始
Windows网络编程的入口是Winsock。它源自BSD套接字接口,经过微软扩展后成为Windows平台上访问TCP/IP等协议的标准方式。使用前调用WSAStartup初始化,结束时调用WSACleanup,这是所有Winsock程序的基本骨架。
套接字分为流式(SOCKSTREAM,对应TCP)和数据报(SOCKDGRAM,对应UDP)。TCP服务端流程通常是socket→bind→listen→accept,客户端则是socket→connect。理解这些调用的顺序和返回码,是排查连接问题的第一步。
阻塞模型的局限
默认套接字是阻塞的:accept、recv、send在条件不满足时会挂起线程。单连接场景下这足够简单,但面对成百上千的连接,为每个连接开一个线程会带来上下文切换和内存开销。于是有了几种改进路径:
- 多线程:每连接一线程,实现直观,但规模受限。
- select模型:用
select同时监视多个套接字,单线程轮询,适合连接数中等的场景。 - 非阻塞套接字:通过
ioctlsocket设置FIONBIO,调用立即返回,需自行处理WSAEWOULDBLOCK。
这些方案各有取舍,select的fd_set有数量上限,且每次调用都要重新填充集合,连接数很大时效率下降明显。
异步I/O与完成端口
真正面向高并发的是重叠I/O(Overlapped I/O)和I/O完成端口(IOCP)。重叠I/O让应用程序发起操作后立即返回,通过事件或回调获知完成;IOCP则把完成通知集中到一个队列,由固定数量的工作线程取出处理。
IOCP的核心思路是:创建完成端口,把套接字关联上去,投递异步操作,工作线程调用GetQueuedCompletionStatus等待完成包。它的优势在于线程数与CPU核心数匹配,避免了大量线程空转,适合服务器端承载大量并发连接。
使用IOCP要注意几点:每个套接字同一时刻只应有一个未完成的操作;完成包中的字节数和错误码要仔细判断;关闭连接时需处理好悬而未决的I/O,避免资源泄漏。
选型建议
技术选型取决于规模与复杂度。连接数少、逻辑简单,阻塞模型加少量线程就够用;中等规模可考虑select或WSAEventSelect;需要支撑大量并发连接时,IOCP是Windows平台上的成熟方案。实际开发中也可借助成熟网络库封装底层细节,把精力放在业务逻辑上。无论选择哪种模型,理解套接字生命周期、错误处理和资源回收,始终是写出稳定网络程序的前提。