BSD 套接字连接 + select(客户端)
BSD socket connect + select (client)
下面的代码肯定有问题,但我似乎无法将客户端连接、非阻塞与 select 语句结合使用。请忽略下面缺少的错误处理。
我好像有两个问题
1. 如果我尝试连接互联网服务器上的端口 80,select 会阻塞直到超时 (60)
2. 总是立即尝试连接 127.0.0.1 上现有或不存在的端口 returns select 无法区分连接成功或失败。
我对 BSD 非阻塞与 select 结合的理解缺少什么?
fd_set readfds;
FD_ZERO(&readfds);
struct timeval tv;
tv.tv_sec = 60;
tv.tv_usec = 0;
struct sockaddr_in dest;
int socketFD = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
dest.sin_port = htons(9483);
long arg;
arg = fcntl(socketFD, F_GETFL, NULL);
arg |= O_NONBLOCK;
fcntl(socketFD, F_SETFL, arg);
if (connect(socketFD, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0 && errno == EINPROGRESS) {
//now add it to the read set
FD_SET(socketFD, &readfds);
int res = select(socketFD+1, &readfds, NULL, NULL, &tv);
int error = errno;
if (res>0 && FD_ISSET(socketFD, &readfds)) {
NSLog(@"errno: %d", error); //Always 36
}
}
errno
是在您最初尝试 connect
时设置的——合法地:也就是说,它正在进行中。然后你调用 select
。因为 select
没有 失败,所以 errno
没有被重置。系统调用仅在失败时设置 errno
;他们不会在成功时清除它。
connect
可能已成功完成。你没有检查那个。您应该使用 SO_ERROR
添加对 getsockopt
的调用以确定它是否有效。这将 return 套接字上的错误状态。
另一个重要说明。根据手册页 (https://www.freebsd.org/cgi/man.cgi?query=connect&sektion=2),您应该使用 writefds
等待 connect
完成。我不知道 readfds
是否会正确报告状态。
[EINPROGRESS] The socket is non-blocking and the connection cannot
be completed immediately. It is possible to select(2)
for completion by selecting the socket for writing.
另见这个非常相似的问题。 Using select() for non-blocking sockets to connect always returns 1
下面的代码肯定有问题,但我似乎无法将客户端连接、非阻塞与 select 语句结合使用。请忽略下面缺少的错误处理。
我好像有两个问题 1. 如果我尝试连接互联网服务器上的端口 80,select 会阻塞直到超时 (60) 2. 总是立即尝试连接 127.0.0.1 上现有或不存在的端口 returns select 无法区分连接成功或失败。
我对 BSD 非阻塞与 select 结合的理解缺少什么?
fd_set readfds;
FD_ZERO(&readfds);
struct timeval tv;
tv.tv_sec = 60;
tv.tv_usec = 0;
struct sockaddr_in dest;
int socketFD = socket(AF_INET, SOCK_STREAM, 0);
memset(&dest, 0, sizeof(dest));
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr("127.0.0.1");
dest.sin_port = htons(9483);
long arg;
arg = fcntl(socketFD, F_GETFL, NULL);
arg |= O_NONBLOCK;
fcntl(socketFD, F_SETFL, arg);
if (connect(socketFD, (struct sockaddr *)&dest, sizeof(struct sockaddr))<0 && errno == EINPROGRESS) {
//now add it to the read set
FD_SET(socketFD, &readfds);
int res = select(socketFD+1, &readfds, NULL, NULL, &tv);
int error = errno;
if (res>0 && FD_ISSET(socketFD, &readfds)) {
NSLog(@"errno: %d", error); //Always 36
}
}
errno
是在您最初尝试 connect
时设置的——合法地:也就是说,它正在进行中。然后你调用 select
。因为 select
没有 失败,所以 errno
没有被重置。系统调用仅在失败时设置 errno
;他们不会在成功时清除它。
connect
可能已成功完成。你没有检查那个。您应该使用 SO_ERROR
添加对 getsockopt
的调用以确定它是否有效。这将 return 套接字上的错误状态。
另一个重要说明。根据手册页 (https://www.freebsd.org/cgi/man.cgi?query=connect&sektion=2),您应该使用 writefds
等待 connect
完成。我不知道 readfds
是否会正确报告状态。
[EINPROGRESS] The socket is non-blocking and the connection cannot
be completed immediately. It is possible to select(2)
for completion by selecting the socket for writing.
另见这个非常相似的问题。 Using select() for non-blocking sockets to connect always returns 1