1

我决定在我的项目中使用 async io 并简单地执行一个单线程循环,在其中我尝试从每个打开的套接字中读取每帧的一些数据。这工作得很好,总的来说我现在对它很满意。问题是我在使用异步套接字时遇到的奇怪问题。

我有这样的代码:

accept a connection...
fcntl(O_NONBLOCK) on the client socket...

int rc;
if((rc = recv(socket))>0)
  process data
if rc == 0
  close socket and cleanup

问题是即使我知道连接没有关闭,有时我也会得到 rc == 0 。如果我不清理,那么我的应用程序将正常工作。但是,如果我进行清理,那么客户端在连接建立之前就会收到断开连接。

所以我的问题是:我是否必须在执行 recv 之前以某种方式检查套接字是否已准备好才能从中获得正确的返回值?

我能找到的大部分信息都是不确定的。我找到了对 select() 的引用,但它似乎会阻塞,直到套接字上的状态发生变化 - 但我需要套接字是非阻塞的。

我正在寻找的只是直观的行为,如果有数据,则将其读取到缓冲区并 recv 返回读取的字节数,如果没有数据则返回-1,如果套接字断开连接,则应返回0。

在调用 recv 以使其按预期工作之前,我是否必须对套接字执行任何其他操作?

4

1 回答 1

1

首先,承担使用套接字服务器“全异步”的繁重工作对于设计来说是一个良好的开端,并且将非常容易地实现可伸缩性。

至于你的问题。

recv() 将返回以下值:

  • recv() 返回的正值表示复制到缓冲区的字节数。(即您实际上收到了这些字节)

  • 当远程端关闭套接字时,recv() 将返回 0。

  • 对于异步套接字,如果连接仍然有效,recv() 将返回 -1 并将 errno 设置为 EAGAIN 或 EWOULDBLOCK,但没有要使用的新数据。在套接字上调用 select() 或 poll() 以等待数据。

  • 否则,任何常规连接失败都将导致 recv() 返回 -1。(你唯一能做的就是关闭套接字)。

所以当你说“rc == 0 有时即使我知道连接没有关闭”时,我怀疑你的伪代码不是检查返回值,而是检查 (rc > 0) 的结果。

这更接近您想要的逻辑:

int rc;
rc = recv(s, buf, buffersize, 0);
if (rc == 0)
{
    /* socket closed by remote end */
    close(s); s=-1;
}
else if ((rc == -1) && ((errno == EAGAIN) || (errno == EWOULDBLOCK)) )
{
   // need to wait.  Call select() or poll()
}
else if (rc == -1)
{
    close(s); s=-1;
}
else
{
    ProcessNewData(s, buffer, rc);
}
于 2013-01-13T06:12:35.793 回答