当我从iOS模拟器(它可能使用与Mac和FreeBSD相同的TCP堆栈)进行非阻塞连接到环回地址时,我发现连接总是成功,即使服务器进程没有运行。
我通过使用select()和零超时来检测连接是否成功。因此,只要select()返回0,我假设连接正在进行中,如果它返回-1我失败并出现错误,如果它返回1,则套接字已准备好读取(因为服务器必须已响应) ,我在报告连接成功后开始阅读。
这适用于除环回之外的所有地址。在环回上,select()总是返回1,即使没有服务器正在运行。所以,我开始阅读,失败了,我处理它。但我应该通过select()!
检测到这一点答案 0 :(得分:3)
您正在<{1}}上收到之前的错误。
在继续connect()
之前,请检查select()
是errno
而不是其他内容。在* BSD中,与EINPROGRESS
上的非监听端口的连接错误输出(或可能错误输出)。
我刚刚运行了一个非常简单的测试(跳过标题):
localhost
没有收听端口int
main(void)
{
int fd;
int r;
struct sockaddr_in remote;
struct hostent *he;
he = gethostbyname("localhost");
if (he == NULL)
return -1;
memcpy(&remote.sin_addr, he->h_addr, sizeof(remote.sin_addr));
remote.sin_port = htons(9671);
remote.sin_family = AF_INET;
fd = socket(PF_INET, SOCK_STREAM, 0);
fcntl(fd, F_SETFL, O_NONBLOCK);
r = connect(fd, (struct sockaddr *)&remote, sizeof remote);
if (r < 0) {
perror("connect");
}
return 0;
}
,我得到了:
9671
connect: Operation now in progress
当然,检查所有系统调用的错误代码始终是一个好主意(上面的例子为了简单起见并不这样做 - 毕竟这只是一个例子)。
答案 1 :(得分:0)
问题是我依靠select()告诉我连接是否成功。选择仅告诉您该fd上是否有更改。我应该在套接字上再次调用connect()并验证它是否失败,errno是EINPROGRESS,ECONN还是EALREADY。除了ECONN之外,所有其他值都意味着我们应该重试; ECONN意味着它已经连接。任何其他errno值意味着我们无法连接。