你们中许多人都知道原始的“send()”不会将您要求的字节数写入网络。您可以轻松地使用指针和循环来确保所有数据都已发送。
但是,在这种情况下,我看不到WSASend()和完成端口的工作方式。它立即返回,您无法控制发送了多少(在例程中可以访问的lpLength中除外)。如何解决?
为了获取所有数据,您是否必须在例程中多次调用WSASend()?这似乎不是一个很大的缺点,特别是如果您希望以特定的顺序输出数据并且多个线程访问这些例程时,这不是一个很大的缺点吗?
最佳答案
当您使用与WSASend
和IOCP
结构相关联的套接字调用OVERLAPPED
时,您实际上会将数据传递给了网络堆栈以进行发送。一旦网络堆栈不再需要您使用的数据缓冲区,网络堆栈将为您提供“完成”。此时,您可以自由地重用或释放用于数据缓冲区的内存。
请注意,在完成完成的那一刻,数据不太可能到达对等方,并且完成的生成只不过意味着网络堆栈已经拥有了缓冲区内容的所有权。
这与send
的操作方式不同。在阻止模式下使用send
时,对send
的调用将一直阻止,直到网络堆栈使用了您提供的所有数据为止。对于在非阻塞模式下调用send
的情况,网络堆栈会从缓冲区中获取尽可能多的数据,然后返回给您有关使用量的详细信息。这意味着您的某些数据已被使用。通常,使用WSASend
会使用所有数据,然后再通知您。
重叠的WSASend
可能由于资源限制或网络错误而失败。失败通常是不正常的,它表明已发送了一些数据,但不是全部。通常情况下,一切都发送正常,或者根本不发送。但是,有可能出现一个错误,该错误表明已使用了一些数据,但未使用全部数据。从这一点开始的方式取决于错误(临时资源限制或硬网络故障)以及该套接字上要挂起的其他WSASend
数量(零或非零)。如果您遇到临时资源错误,并且对此套接字没有其他未完成的WSASend
调用,则只能尝试发送其余数据。而且由于您不知道临时资源限制情况何时会过去而使情况变得更加复杂...如果您曾经有临时资源限制引起的部分发送,并且确实有其他WSASend
调用挂起,那么您应该中止通过从此WSASend
调用发送部分缓冲区,然后发送随后的WSASend
调用的所有(或部分),您的数据流可能会出现乱码。
请注意,在套接字上进行多个未完成的WSASend
调用是a)有用和b)高效的。这是保持连接充分利用的唯一方法。但是,您应该意识到一次处理多个重叠的WSASend
调用(请参阅here)对内存和资源使用的影响,因为您可以有效地控制缓冲区的生存期(因此可以控制内存和资源的数量)。由于TCP流量控制问题,您的代码使用了)。如果您想变得非常聪明,请参阅SIO_IDEAL_SEND_BACKLOG_QUERY
和SIO_IDEAL_SEND_BACKLOG_CHANGE
...