在读取缓冲区已满时使用 select 检查可写套接字

Posted

技术标签:

【中文标题】在读取缓冲区已满时使用 select 检查可写套接字【英文标题】:Check socket writeable with select while read buffer full 【发布时间】:2016-09-16 04:16:40 【问题描述】:

我正在尝试在使用send 之前检查套接字是否可写。这工作正常,除非套接字的读取缓冲区已满,然后 select 超时(至少这是我所期望的,行为是在不使用 recv 向套接字发送大量数据后,select 返回0.如果我读了一些东西再试一次,它会再次正常运行)。我希望完整的读取缓冲区不会阻止发送。我做错了什么?

int testwriteable(SOCKET socket) 
  timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = 100; //100 us (microseconds)

  fd_set set;
  FD_ZERO(&set);
  FD_SET(socket, &set);

  //check for writable
  return select(1, NULL, &set, NULL, &timeout);

【问题讨论】:

无法重现(Win 10 64 位,VS 2015 R3)。这整个函数给我的印象是perverse,你为单个套接字做了很多工作,返回的信息的值是可疑的。大概您正在检查返回 SOCKET_ERROR 的函数,并且您没有假设因为套接字是可写的,它将接受 所有 您要呈现给它的数据? 【参考方案1】:

如果select() 使用此代码超时,则表示在整个超时期间发送缓冲区已满。

但是你做错了。您应该有一个主要的 select() 循环来驱动您的代码,而不是这种控制反转,并且您应该 (a) 在有东西要写的时候写,(b) 检测它何时返回 -1/EWOULDBLOCK/EAGAIN,并且(c) 此时将套接字 FD 添加到 writeFDs 集并推迟写入直到套接字变为可写。发生这种情况时,重试写入(这意味着您已将数据及其长度排队到某处),如果成功,则从 writeFDs 中删除套接字 FD。

【讨论】:

means the send buffer was full,有点迂腐,表示sendsendtoWSASendto会阻塞,也可能是因为非阻塞connect()没有完成. @kfsone 正确。然而,在这种情况下,他知道他的读取缓冲区已满,这意味着一个完整的连接。 我认为问题来自最终在读取缓冲区已满时阻止发送的另一方。由于另一端的发送部分是调试测试,它在读取线程上发送并阻塞,导致发送缓冲区最终确实填满,直到数据被读取。我不确定select 和其他事情是如何工作的,这会导致对问题的误解。感谢您指出正确的做事方式,我什至不知道ioctlsocket(在 Windows 上)并且会读一点然后尝试重写部分代码。我一般不写c++/winapi代码。

以上是关于在读取缓冲区已满时使用 select 检查可写套接字的主要内容,如果未能解决你的问题,请参考以下文章

除了缓冲区已满,EAGAIN 会在发送时返回吗?

UDP套接字缓冲区溢出检测

zabbix 由于系统缓冲区空间不足或队列已满,不能执行套接字上的操作

底部 4GB 已满时 FileDialog 崩溃

select()函数

套接字描述符就绪条件