- 论坛徽章:
- 0
|
在网络编程中经常要用到非阻塞式的socket,尤其在一些嵌入式场合。翻看了一下linux的man[man connect],有这么一段话:
EINPROGRESS
The socket is non-blocking and the connection cannot be completed immediately. It is possible to select(2) or poll(2) for completion by selecting the socket for writing. After select(2) indicates writability, use getsockopt(2) to read the SO_ERROR option at level SOL_SOCKET to determine whether connect() completed successfully (SO_ERROR is zero) or unsuccessfully (SO_ERROR is one of the usual error codes listed here, explaining the reason for the failure).
大致意思就是说对于非阻塞式的socket,由于不能立即完成connect操作(比如TCP的三次握手),会返回EINPROGRESS这个errno,我们应该认为这是正常的,然后用select或poll调用来确定是否可写(这里就可以设置多长时间之内可写来达到不会等待很久,如果不是非阻塞式的socket,系统回尝试很多次之后才返回失败,具体多长时间跟OS有关),也就是说,不管成功还是失败,都会可写,那怎么区分呢?用getsockopt()调用来确认errno,如果errno不为0(success),就可以判断为失败。
以下是一个模板:
int fd = socket(AF_INET, SOCK_STREAM, 0);
if (fd < 0)
{
fprintf(stderr, "socket() failed: %s\n", strerror(errno));
goto error_quit;
}
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK) < 0) //非阻塞
{
fprintf(stderr, "fcntl() failed: %s\n", strerror(errno));
goto error_quit;
}
.......bind()之类的操作
struct sockaddr_in server_addr;
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = htonl(server_ip); //转换为网络字节序
server_addr.sin_port = htons(server_port);
retval = connect(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
if (retval < 0)
{
struct timeval = {1, 5000}; //在1.005s内还没有返回则认为失败
fd_set writeable;
//返回EINPROGRESS是正常的,因为3次TCP握手还在进行中
if (errno != EINPROGRESS)
{
fprintf(stderr, "connect() failed: %s\n", strerror(errno));
goto error_quit;
}
FD_ZERO(&writeable);
FD_SET(fd, &writeable);
//连接成功或者失败都会writeable
retval = select(fd+1, NULL, &writeable, NULL, &tv);
FD_CLR(fd, &writeable);
if (retval < 0)
{
//调用失败
fprintf(stderr, "select() failed: %s\n", strerror(errno));
goto error_quit;
}
else if (retval == 0)
{
//超时,在规定时间内还不能可写
goto error_quit;
}
else
{
int error = 0;
socklen_t len = sizeof(int);
//成功的话error应该为0
if ((getsockopt(fd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) || (0 != error))
{
fprintf(stderr, "connect failed: %s\n", strerror(error));
goto error_quit;
}
}//select
}//connect
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/83058/showart_1431458.html |
|