0

当我打开O_NONBLOCK我的连接 len 返回0并且我的 errno 返回EIO。我期待 len 是-1并且 errno 是 EAGAIN。根据我得到的信息,我可以假设初始连接存在问题。我不明白为什么我会得到它。如果我注释掉我打开的位置,O_NONBLOCK我根本没有这个问题。我在打开方面错过了什么O_NONBLCOK吗?

我的代码(主())

long len;

//Var for O_NONBLOCKING
int flags;

printf("R thread - starting\n");

MainTcpipIndex = TcpipIndex = 0;
while ( fMainShutdown == FALSE )
  {

  s_MuxWait(5000, "", &hevTcpipBuffAvail[MainTcpipIndex], 0);
  if ( hevTcpipBuffAvail[MainTcpipIndex] == 0)
     continue;

  len = s_recv( lSocket, TcpipRecord[MainTcpipIndex].TcpipBuffer,
              sizeof(TcpipRecord[MainTcpipIndex].TcpipBuffer));

    //initialize flags var      
  flags = fcntl(lSocket, F_GETFL, 0);

  //turns on O_NONBLOCKING
  fcntl(lSocket, F_SETFL, flags | O_NONBLOCK);

  if (len == -1  ||  len == 0 && errno != EAGAIN)  //0 = connection broken by host
     {
         ReceiveError = errno;
         hevReceiveError = 1;
         printf("R_main - set hevReceiveError ON\n");
         pthread_exit(NULL);
     }
 //catches O_NONBLOCK
 if (len == -1 && errno == EAGAIN)
     {
         LogMessage(&LogStruct, INFO, LOGQUEUE + LOGSCREEN, "Caught the
                     O_NONBLOCKING\n");
         len = 0;
         continue;
     }

  // Record Length
  TcpipRecord[MainTcpipIndex].ulTcpipBufLen = len;

  // Tell T Thread we have a message
  hevTcpipBuffUsed[MainTcpipIndex] = 1;
  hevTcpipBuffAvail[MainTcpipIndex] = 0;

  // Maintain Index
  if ( ++MainTcpipIndex >= MAX_TCPIP_BUFFS )
     MainTcpipIndex = 0;

  }//end while

编辑

也许我第一次没有说清楚,我知道errno和len与s_recv 我的问题是我打开O_NONBLOCK时得到了不想要的结果;s_recv的 errno 是 EIO,它的 len 是 0。如果我关闭,O_NONBLOCK那么我的所有问题都会消失;len 为 1 或更大,不需要检查 errno。

以下是我期望的场景示例:

在第一个坏情况下s_recv,Len 为 0 或 -1,errno 不是 EAGAIN,连接被重置。

在第二个坏场景s_recv中,Len 是-1,errno 是 EAGAIN。这是根据手册页打开 O_NONBLOCK 时的预期场景。

在好的场景s_recv中 len 大于 1 不需要检查 errno。

4

2 回答 2

1

在下一次阅读之前,更改O_NONBLOCK为不相关。

因此,您必须在调用之前检查lenand 。当然,您必须检查返回值,因为它也可能会失败。errno fcntlfcntl

总而言之,len == 0errno == EIO更改为 无关O_NONBLOCK,但与s_recv之前有关。

此外,请注意您的

if (len == -1 || len == 0 && errno != EAGAIN)

是相同的

if (len == -1 || (len == 0 && errno != EAGAIN) )

这是没有意义的,因为如果返回值不是 -1, errno 必须被忽略。如果返回值为0,则对等方已关闭连接。

更新

我已经构建了一个简单的回显客户端

fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd == -1)
    error("socket");

he = gethostbyname("localhost");
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = ((struct in_addr*)he->h_addr)->s_addr;
addr.sin_port = htons(7); /* echo */
if (connect(fd, (struct sockaddr*) &addr, sizeof(addr)) == -1)
    error("connect");

while (fgets(buf, sizeof(buf), stdin)) {
    n = strlen(buf);
    printf("fgets=%d, %s", n, buf);
    if (send(fd, buf, n, 0) == -1)
        error("send");

    n = recv(fd, buf, sizeof(buf), 0);
    if (n == -1)
        error("recv");

    printf("recv=%d, %s", n, buf);

    flags = fcntl(fd, F_GETFL, 0);
    printf("flags=%d\n", flags);
    if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
        error("fcntl");
}

设置后O_NONBLOCK,我收到

errno=11
recv: 资源暂时不可用

如果我fcntl(O_NONBLOCK)在循环之前移动,一切正常。

因此,在读取或写入套接字之后摆弄非阻塞似乎是不可取的。

于 2013-02-11T22:19:45.293 回答
0

问题是这条线:

if (len == -1  ||  len == 0 && errno != EAGAIN)

这相当于

if (len == -1  ||  (len == 0 && errno != EAGAIN))

因此,如果没有可用的数据 ( len == -1),您将不会检查errno,只会无条件地标记错误并退出。此外,当存在 EOF ( len == 0) 时,不会设置 errno,因此检查它会给出之前调用中发生的任何事情。

你可能想要:

if ((len < 0 && errnor != EGAIN) || len == 0) {
    ReceiveError = (len < 0) ? errno : 0;

此外,如果 fcntl 出现错误,则会破坏 errno(尽管我预计不会发生这种情况 - 使用 GETFL/SETFL 可能会看到的唯一失败是 EBADF。)您可能希望在调用 recv 之前执行 fcntl 调用.

于 2013-02-12T18:17:50.817 回答