在完成端口中调用WSASend()?

use*_*454 3 c++ sockets io networking winsock

你们中的许多人都知道原来的"send()"不会写入你要求它的字节数.您可以轻松地使用指针和循环来确保所有数据都已发送.

但是,我没有看到WSA​​Send()和完成端口在这种情况下是如何工作的.它会立即返回,您无法控制发送的数量(除了您在例程中有权访问的lpLength).这是如何解决的?

您是否需要多次在例程中调用WSASend()以获取所有数据?这看起来不是一个很大的缺点,特别是如果您希望以特定顺序输出数据并且多个线程访问例程?

Len*_*ate 7

当您WSASend使用与a IOCPOVERLAPPED结构关联的套接字进行调用时,您实际上会将数据传递到网络堆栈以进行发送.一旦您使用的数据缓冲区不再需要网络堆栈,网络堆栈将为您提供"完成".此时,您可以自由地重用或释放用于数据缓冲区的内存.

请注意,在生成完成时,数据不太可能已到达对等体,并且完成的生成仅意味着网络堆栈已取得缓冲区内容的所有权.

这与send操作方式不同.随着send阻塞模式调用send将阻塞,直到网络堆栈使用了所有你所提供的数据.对于send非阻塞模式下的调用,网络堆栈从缓冲区中获取尽可能多的数据,然后返回给您,详细说明它使用了多少; 这意味着您的一些数据已被使用.与WSASend一般,所有的数据被通知您之前使用.

WSASend由于资源限制或网络错误,重叠可能会失败.获得失败表示某些数据已发送但并非全部发送,这是不寻常的.通常它都发送好或根本没发送.但是,可能会出现错误,表示已使用某些数据,但并非全部.从这一点开始如何进行取决于错误(临时资源限制或硬网络故障)以及WSASend您在该套接字上有多少其他待处理(零或非零).如果您有临时资源错误而没有其他未完成WSASend的此套接字调用,则只能尝试发送其余数据; 而且由于你不知道临时资源限制情况何时会通过这一事实而变得更加复杂...如果你有一个临时的资源限制导致部分发送而你还有其他WSASend呼叫未决,那么你应该中止连接,因为您可能通过从此WSASend调用发送部分缓冲区然后发送后续WSASend调用的全部(或部分)来使您的数据流混乱.

请注意,a)有用且b)WSASend在套接字上具有多个未完成的调用.这是保持连接充分利用的唯一方法.但是,您应该知道WSASend一次有多个重叠调用挂起的内存和资源使用影响(请参阅此处),因为您正在处理缓冲区生命周期的控制(以及因此您的内存和资源量)由于TCP流控制问题,代码使用)到对等方.看SIO_IDEAL_SEND_BACKLOG_QUERY,SIO_IDEAL_SEND_BACKLOG_CHANGE如果你想变得非常聪明......


val*_*ldo 0

首先关于send. 实际上,可能会发生两种不同的情况,具体取决于套接字的配置方式。

如果套接字处于所谓的阻塞模式(默认) - 的调用send阻塞调用线程,直到底层网络驱动程序消耗完所有输入缓冲区。(请注意,这并不意味着数据已经到达对等方)。

如果套接字转换为非阻塞模式 -如果底层驱动程序可能不会立即消耗所有输入,则调用send失败。在这种情况下的GetLastError回报。WSAEWOULDBLOCK应用程序应等待,直到可以重试发送。send应用程序应该从系统获取有关套接字状态更改的通知,而不是循环调用。诸如WSAEventSelect或 之类的函数WSAAsyncSelect可用于此目的(以及legacy select)。

现在,有了 I/O 完成端口,WSASend情况就有些不同了。当套接字与完成端口关联时 - 它会自动转换为非阻塞模式。

如果对的调用WSASend无法立即完成(即网络驱动程序无法消耗所有输入),则WSASend返回错误并GetLastError返回STATUS_PENDING. 这实际上意味着异步操作已经开始但尚未完成**。

也就是说,您不应该WSASend重复调用,因为发送操作已经在进行中。当它完成时(无论成功与否),您将在 I/O 完成端口上收到通知,但同时调用线程可以自由地执行其他操作。