我编写了以下代码。我创建一个套接字,并使用select()
监视此新创建的套接字。在select()
调用之后,此套接字被检测为可读写。
如何解释这种现象?与套接字recvbuf / sndbuf和recvlowat / sndlowat有关系吗?
#include <iostream>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/select.h>
#include <sys/time.h>
int main()
{
int nClientFd = socket(AF_INET, SOCK_STREAM, 0);
if (nClientFd == -1)
{
std::cout << "create socket failed, errno: " << errno << std::endl;
return -1;
}
fd_set readFdSet;
FD_ZERO(&readFdSet);
FD_SET(nClientFd, &readFdSet);
fd_set writeFdSet;
FD_ZERO(&writeFdSet);
FD_SET(nClientFd, &writeFdSet);
struct timeval stTimeout;
stTimeout.tv_sec = 1;
stTimeout.tv_usec = 0;
if (select(nClientFd + 1, &readFdSet, &writeFdSet, nullptr, &stTimeout) == -1)
{
std::cout << "select failed" << std::endl;
close(nClientFd);
return -1;
}
if (FD_ISSET(nClientFd, &readFdSet))
{
std::cout << "socket is readable" << std::endl;
}
if (FD_ISSET(nClientFd, &writeFdSet))
{
std::cout << "socket is writable" << std::endl;
}
close(nClientFd);
return 0;
}
输出:
socket is readable
socket is writable
答案 0 :(得分:2)
首先,Linux / glibc的select()
被记录为有时会虚假地报告文件描述符以使其可读,但是我们不需要依靠它来解释行为。
主要问题似乎是您误解了select()
在提供的读取或写入fd集之一中设置文件描述符的含义。这并不一定意味着可以通过fd成功传输数据。相反,这意味着fd进入或已经处于尝试不会被阻止的状态,包括这样的尝试将在没有阻止的情况下失败的情况。 Linux,尤其是POSIX文档在这一点上很清楚。
在这种情况下,您描述的行为正是我所期望的。您已经创建了面向流的套接字,但未将其连接到对等方,因此我期望read()
和write()
对其进行的尝试立即失败。因此,select()
有权在其读写fd集中返回其文件描述符。