免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1618 | 回复: 0
打印 上一主题 下一主题

关于非阻塞式socket的connect [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2008-11-19 20:05 |只看该作者 |倒序浏览

                                               
    在网络编程中经常要用到非阻塞式的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
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP