当我打开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
的错误是EIO及其
len是0.如果我关闭O_NONBLOCK
那么我的所有问题都会消失; len是1或更多而errno不是
需要检查。
以下是我期望的场景示例:
在第一个错误情况s_recv
中,Len为0或-1,errno不是EAGAIN,连接已重置。
在第二个不好的情况s_recv
中,Len是-1而errno是EAGAIN。这是什么时候的预期场景
O_NONBLOCK基于手册页打开。
在好的sceanrio s_recv
中,len超过1并且没有必要检查errno。
答案 0 :(得分:1)
在下一次阅读之前,对O_NONBLOCK
的更改无关紧要。
因此,在致电len
之前,您必须先检查errno
和fcntl
。当然,您必须检查fcntl
的返回值,因为它也可能会失败。
总结一下,len == 0
和errno == EIO
与O_NONBLOCK
的更改无关,而是与s_recv
之前的更改无关。
此外,请注意您的
if (len == -1 || len == 0 && errno != EAGAIN)
与
相同if (len == -1 || (len == 0 && errno != EAGAIN) )
这没有意义,因为如果返回值不 -1
,则必须忽略errno。如果返回值为0
,则对等方已关闭连接。
<强>更新强>:
我已经构建了一个简单的echo客户端
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
后,我收到了
错误号= 11
recv:资源暂时不可用
如果我在循环之前移动fcntl(O_NONBLOCK)
,一切正常。
因此,在读取或写入套接字后,似乎不建议使用非阻塞。
答案 1 :(得分: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出现错误,那将会破坏错误(虽然我预计不会发生这种情况 - 您可能会看到GETFL / SETFL唯一的失败是EBADF。)您可能想要在recv调用之前执行fcntl调用。