如何处理异步套接字上的所有可能错误?

时间:2013-01-13 05:54:32

标签: linux sockets unix

我决定在我的项目中使用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以使其按预期工作之前,我是否必须对套接字执行任何其他操作?

1 个答案:

答案 0 :(得分: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);
}