erron

关于非阻塞式socket的connect
 
 

    在网络编程中经常要用到非阻塞式的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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值