<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>IOCP on JasperSao的博客</title><link>https://jasperstonnne.github.io/MyBlog/tags/iocp/</link><description>Recent content in IOCP on JasperSao的博客</description><generator>Hugo -- gohugo.io</generator><language>zh-cn</language><lastBuildDate>Sun, 30 Aug 2026 08:12:59 +0000</lastBuildDate><atom:link href="https://jasperstonnne.github.io/MyBlog/tags/iocp/index.xml" rel="self" type="application/rss+xml"/><item><title>IOCP：Windows 异步机制</title><link>https://jasperstonnne.github.io/MyBlog/p/iocp-windows-async-io/</link><pubDate>Thu, 20 Aug 2026 00:00:00 +0800</pubDate><guid>https://jasperstonnne.github.io/MyBlog/p/iocp-windows-async-io/</guid><description>&lt;img src="https://jasperstonnne.github.io/MyBlog/p/iocp-windows-async-io/cover.svg" alt="Featured image of post IOCP：Windows 异步机制" /&gt;&lt;h2 id="一网络编程要解决什么问题"&gt;一、网络编程要解决什么问题&#10;&lt;/h2&gt;&lt;p&gt;在 C/S 模式中，服务端通常先执行：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;socket -&amp;gt; bind -&amp;gt; listen&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;客户端也会先创建 socket。各种网络模型前面的准备过程基本相同，主要区别在后续如何处理连接和 I/O。&lt;/p&gt;&#10;&lt;p&gt;网络编程中有四件无法预先确定的事情：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;客户端什么时候建立连接；&lt;/li&gt;&#10;&lt;li&gt;客户端什么时候断开连接；&lt;/li&gt;&#10;&lt;li&gt;客户端什么时候发送数据；&lt;/li&gt;&#10;&lt;li&gt;数据什么时候能够写入发送缓冲区。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;因此，网络编程主要解决四类问题：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;连接的建立；&lt;/li&gt;&#10;&lt;li&gt;连接的断开；&lt;/li&gt;&#10;&lt;li&gt;数据的接收；&lt;/li&gt;&#10;&lt;li&gt;数据的发送。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;每个 socket 都对应接收缓冲区（receive buffer）和发送缓冲区（send buffer）。&lt;code&gt;write&lt;/code&gt; 只负责把数据从用户态复制到内核态的发送缓冲区；数据什么时候到达对端、如何到达对端，属于网络协议栈要解决的问题。&lt;/p&gt;&#10;&lt;p&gt;常见的网络模型包括：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;阻塞 I/O 模型；&lt;/li&gt;&#10;&lt;li&gt;Reactor；&lt;/li&gt;&#10;&lt;li&gt;Proactor（IOCP）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="二阻塞-io-与-reactor"&gt;二、阻塞 I/O 与 Reactor&#10;&lt;/h2&gt;&lt;p&gt;一次 I/O 可以分成两个阶段：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;I/O 检测&lt;/strong&gt;：判断 I/O 是否就绪；&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;I/O 操作&lt;/strong&gt;：真正执行 &lt;code&gt;accept&lt;/code&gt;、&lt;code&gt;read&lt;/code&gt;、&lt;code&gt;write&lt;/code&gt;、&lt;code&gt;connect&lt;/code&gt; 等操作。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="1-阻塞-io"&gt;1. 阻塞 I/O&#10;&lt;/h3&gt;&lt;p&gt;阻塞 I/O 通过阻塞当前线程来等待 I/O 就绪，从而解决“不知道事件什么时候发生”的问题。&lt;/p&gt;&#10;&lt;p&gt;阻塞和非阻塞主要描述 I/O 检测阶段：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;阻塞：I/O 没有就绪时，线程会等待；&lt;/li&gt;&#10;&lt;li&gt;非阻塞：I/O 没有就绪时，函数立即返回。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="2-reactor"&gt;2. Reactor&#10;&lt;/h3&gt;&lt;p&gt;Reactor 使用：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;I/O 多路复用（检测 I/O）+ 非阻塞 I/O（操作 I/O）&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;它先注册事件。当事件触发时，系统发出就绪通知，用户层收到通知后，再调用 POSIX I/O 函数完成操作。因此，Reactor 属于：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;同步 I/O + 异步事件通知&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;select&lt;/code&gt;、&lt;code&gt;poll&lt;/code&gt;、&lt;code&gt;epoll&lt;/code&gt; 用于同时检测多路 I/O 是否就绪，它们只负责 I/O 检测；Reactor 则包含 I/O 检测和后续的 I/O 操作。&lt;/p&gt;&#10;&lt;p&gt;所以它们的关系是：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;Reactor = select/poll/epoll 等 I/O 多路复用 + 非阻塞 I/O 操作&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h2 id="三iocp-与-reactor-的区别"&gt;三、IOCP 与 Reactor 的区别&#10;&lt;/h2&gt;&lt;p&gt;IOCP（I/O Completion Port，I/O 完成端口）是 Windows 提供的一种高效异步 I/O 机制。&lt;/p&gt;&#10;&lt;p&gt;Reactor 的过程：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;注册事件&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内核检测到 I/O 就绪&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户层收到就绪通知&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户层调用 accept/read/write 等函数完成 I/O&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这是一种&lt;strong&gt;就绪通知&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;IOCP 的过程：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户层投递异步 I/O 请求&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内核检测并完成 I/O&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;用户层收到完成通知&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;因此：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;Reactor：同步 I/O、异步事件；&lt;/li&gt;&#10;&lt;li&gt;IOCP：异步 I/O、异步事件。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;两者都是为了解决网络 I/O 问题，因此 IOCP 在整体概念上更接近 Reactor；但 IOCP 并不是 &lt;code&gt;select&lt;/code&gt;、&lt;code&gt;poll&lt;/code&gt;、&lt;code&gt;epoll&lt;/code&gt; 这样的 I/O 多路复用机制。&lt;/p&gt;&#10;&lt;p&gt;在 Reactor 中，即使 socket 已经就绪，真正的数据复制仍由用户线程调用 I/O 函数完成。IOCP 则由用户层发起异步操作，由内核完成 I/O；在此期间，用户线程可以处理其他任务。&lt;/p&gt;&#10;&lt;h2 id="四iocp-的工作原理"&gt;四、IOCP 的工作原理&#10;&lt;/h2&gt;&lt;p&gt;网络 I/O 属于外设资源，相关数据需要通过系统调用，由内核进行操作。&lt;/p&gt;&#10;&lt;p&gt;IOCP 的基本流程如下：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;使用 &lt;code&gt;CreateIoCompletionPort&lt;/code&gt; 创建完成端口；&lt;/li&gt;&#10;&lt;li&gt;将 socket 与 IOCP 绑定；&lt;/li&gt;&#10;&lt;li&gt;投递异步 I/O 操作；&lt;/li&gt;&#10;&lt;li&gt;内核进行 I/O 检测和 I/O 操作；&lt;/li&gt;&#10;&lt;li&gt;操作完成后，内核把完成信息放入完成队列；&lt;/li&gt;&#10;&lt;li&gt;用户层通过 &lt;code&gt;GetQueuedCompletionStatus&lt;/code&gt; 取得完成通知。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;常见的异步操作包括：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;AcceptEx&lt;/code&gt;：接受连接；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;ConnectEx&lt;/code&gt;：主动建立连接；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;DisconnectEx&lt;/code&gt;：主动断开连接；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WSARecv&lt;/code&gt;：接收数据；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WSASend&lt;/code&gt;：发送数据。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;例如建立连接时：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;socket 绑定 IOCP&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;投递 AcceptEx&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;内核完成连接接收&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;GetQueuedCompletionStatus 取得完成通知&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;与传统 &lt;code&gt;accept&lt;/code&gt; 不同，&lt;code&gt;AcceptEx&lt;/code&gt; 是预先投递的异步请求。服务器可以在启动时投递多个 &lt;code&gt;AcceptEx&lt;/code&gt;，从而并发接收多条连接。&lt;/p&gt;&#10;&lt;h3 id="iocp-与线程池"&gt;IOCP 与线程池&#10;&lt;/h3&gt;&lt;p&gt;IOCP 通常会绑定一个线程池。&lt;/p&gt;&#10;&lt;p&gt;当线程调用 &lt;code&gt;GetQueuedCompletionStatus&lt;/code&gt; 时，该线程会与 IOCP 产生关联。线程退出或关闭后，关联取消；一个线程只能关联一个 IOCP。&lt;/p&gt;&#10;&lt;p&gt;&lt;code&gt;GetQueuedCompletionStatus&lt;/code&gt; 是阻塞接口：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;等待完成队列出现数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;取得完成状态&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ↓&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;在用户态处理完成事件&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;最后可以使用 &lt;code&gt;CloseHandle&lt;/code&gt; 关闭 I/O 完成端口句柄。&lt;/p&gt;&#10;&lt;h2 id="五完成事件如何与连接关联"&gt;五、完成事件如何与连接关联&#10;&lt;/h2&gt;&lt;p&gt;收到完成通知后，需要知道是哪一条连接、哪一次操作完成了。&lt;/p&gt;&#10;&lt;h3 id="1-reactor-中的关联方式"&gt;1. Reactor 中的关联方式&#10;&lt;/h3&gt;&lt;p&gt;以 &lt;code&gt;epoll&lt;/code&gt; 为例，注册事件时可以把一个值交给内核保存：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;也可以关联用户态指针：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="n"&gt;ev&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ptr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;epoll_wait&lt;/code&gt; 返回事件时会带回这个值，因此可以判断是哪一条连接发生了事件。&lt;/p&gt;&#10;&lt;h3 id="2-iocp-中的关联方式"&gt;2. IOCP 中的关联方式&#10;&lt;/h3&gt;&lt;p&gt;IOCP 有两种关联信息。&lt;/p&gt;&#10;&lt;p&gt;第一种是 &lt;code&gt;CreateIoCompletionPort&lt;/code&gt; 的第三个参数 &lt;code&gt;CompletionKey&lt;/code&gt;。它可以保存一个用户态指针，并在其中记录 socket 等连接信息。&lt;/p&gt;&#10;&lt;p&gt;第二种是异步函数最后传入的 &lt;code&gt;OVERLAPPED&lt;/code&gt; 指针。可以把 &lt;code&gt;OVERLAPPED&lt;/code&gt; 放进自定义结构体：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-cpp" data-lang="cpp"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="nc"&gt;OverlappedPerIO&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;OVERLAPPED&lt;/span&gt; &lt;span class="n"&gt;overlapped&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="n"&gt;SOCKET&lt;/span&gt; &lt;span class="n"&gt;socket&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="c1"&gt;// 其他与本次 I/O 相关的数据&#10;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="p"&gt;};&lt;/span&gt;&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;内核使用其中的 &lt;code&gt;OVERLAPPED&lt;/code&gt;，用户层则可以在结构体中附加需要关联的数据。&lt;/p&gt;&#10;&lt;p&gt;可以这样理解：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;CompletionKey&lt;/code&gt;：关联连接级信息；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;OVERLAPPED*&lt;/code&gt;：关联某一次 I/O 操作的信息。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h2 id="六重叠-io"&gt;六、重叠 I/O&#10;&lt;/h2&gt;&lt;p&gt;异步 I/O 是投递请求后无需原地等待，可以由其他线程等待完成通知。&lt;/p&gt;&#10;&lt;p&gt;重叠 I/O 是指：无需等待上一个 I/O 完成，就可以继续投递下一个操作，让多个操作同时处于进行状态。&lt;/p&gt;&#10;&lt;p&gt;例如，如果每次只投递一个 &lt;code&gt;AcceptEx&lt;/code&gt;，完成一次后再投递下一次，那么客户端较多时，建立连接的效率会比较低。服务器可以在启动时投递多个 &lt;code&gt;AcceptEx&lt;/code&gt;：&lt;/p&gt;&#10;&lt;div class="highlight"&gt;&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-text" data-lang="text"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AcceptEx 请求 1 ─┐&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AcceptEx 请求 2 ─┼─→ 同时等待多个客户端连接&#10;&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;AcceptEx 请求 3 ─┘&#10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;每个重叠 I/O 都使用一个独立的 &lt;code&gt;OVERLAPPED&lt;/code&gt; 结构。操作完成后，&lt;code&gt;GetQueuedCompletionStatus&lt;/code&gt; 会返回对应的 &lt;code&gt;OVERLAPPED*&lt;/code&gt;，用户层据此找到这次操作的上下文。&lt;/p&gt;&#10;&lt;h2 id="七连接断开的判断"&gt;七、连接断开的判断&#10;&lt;/h2&gt;&lt;p&gt;客户端主动断开连接时，可以通过以下方式判断。&lt;/p&gt;&#10;&lt;h3 id="reactor"&gt;Reactor&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;epoll_wait&lt;/code&gt; 返回 &lt;code&gt;EPOLLHUP&lt;/code&gt; 或 &lt;code&gt;EPOLLRDHUP&lt;/code&gt;；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;read&lt;/code&gt; / &lt;code&gt;recv&lt;/code&gt; 返回 &lt;code&gt;0&lt;/code&gt;。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="iocp"&gt;IOCP&#10;&lt;/h3&gt;&lt;ol&gt;&#10;&lt;li&gt;&lt;code&gt;GetLastError&lt;/code&gt; 返回相关错误，例如异常断开时的 &lt;code&gt;ERROR_NETNAME_DELETED&lt;/code&gt;；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;GetQueuedCompletionStatus&lt;/code&gt; 返回的完成字节数 &lt;code&gt;dwBytes == 0&lt;/code&gt;。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;超时情况下还可能出现 &lt;code&gt;WAIT_TIMEOUT&lt;/code&gt;。&lt;/p&gt;&#10;&lt;h2 id="八投递操作"&gt;八、投递操作&#10;&lt;/h2&gt;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;AcceptEx&lt;/code&gt; 可以多次投递，以并发接收连接；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WSARecv&lt;/code&gt; 涉及接收顺序和线程安全问题；&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;WSASend&lt;/code&gt; 可以多次投递。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>