美文网首页
linux下connect阻塞处理

linux下connect阻塞处理

作者: 自如如是 | 来源:发表于2019-05-14 16:35 被阅读0次

主要参考https://www.cnblogs.com/Anker/p/6413642.html


一,问题:

我在做一个tcp通信的项目,负责客户端,使用非阻塞connect遇到connect阻塞的问题,使用阻塞connect则遇到 EINPROGRESS的错误,需要找到办法解决。特此记录以作学习所用。

二,非阻塞和阻塞connect

对于阻塞式套接字,调用connect函数将激发TCP的三次握手过程,而且仅在连接建立成功或者出错时才返回,阻塞时长几十秒到几分钟不等;
对于非阻塞式套接字,如果调用connect函数会之间返回-1(表示出错),且错误为EINPROGRESS,表示连接建立,建立启动但是尚未完成;
如果返回0,则表示连接已经建立,这通常是在服务器和客户在同一台主机上时发生。

三,解决方法:

select是一种IO多路复用机制,它允许进程指示内核等待多个事件的任何一个发生,并且在有一个或者多个事件发生或者经历一段指定的时间后才唤醒它。connect本身并不具有设置超时功能,如果想对套接字的IO操作设置超时,可使用select函数。

对于select和非阻塞connect,注意两点:[1] 当连接成功建立时,描述符变成可写; [2] 当连接建立遇到错误时,描述符变为即可读,也可写,遇到这种情况,可调用getsockopt函数。

四,实现步骤:

(1) 创建socket,并利用fcntl将其设置为非阻塞
(2) 调用connect函数,如果返回0,则连接建立;如果返回-1,检查errno ,如果值为 EINPROGRESS,则连接正在建立;
(3) 为了控制连接建立时间,将该socket描述符加入到select的可读可写集合中,采用select函数设定超时;
(4) 如果规定时间内成功建立,则描述符变为可写;否则,采用getsockopt函数捕获错误信息;
(5) 恢复套接字的文件状态并返回。

测试代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <errno.h>

int main(int argc, char **argv)
{
    if (argc < 3) {
        printf("please input ip and port, for example ./main 120.12.34.56 80.\n");
        return -1;
    }

    char *ipaddr = argv[1];
    unsigned int port = atoi(argv[2]);
    int fd = 0;
    struct sockaddr_in  addr;
    fd_set fdr, fdw;
    struct timeval timeout;
    int err = 0;
    int errlen = sizeof(err);
    fd = socket(AF_INET,SOCK_STREAM,0);
    if (fd < 0) {
        fprintf(stderr, "create socket failed,error:%s.\n", strerror(errno));
        return -1;
    }

    bzero(&addr, sizeof(addr));
    addr.sin_family = AF_INET;
    addr.sin_port = htons(port);
    inet_pton(AF_INET, ipaddr, &addr.sin_addr);
    /*设置套接字为非阻塞*/
    int flags = fcntl(fd, F_GETFL, 0);
    if (flags < 0) {
        fprintf(stderr, "Get flags error:%s\n", strerror(errno));
        close(fd);
        return -1;
    }

    flags |= O_NONBLOCK;
    if (fcntl(fd, F_SETFL, flags) < 0) {
        fprintf(stderr, "Set flags error:%s\n", strerror(errno));
        close(fd);
        return -1;
    }

    /*阻塞情况下linux系统默认超时时间为75s*/
    int rc = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
    if (rc != 0) {
        if (errno == EINPROGRESS) {
            printf("Doing connection.\n");
            /*正在处理连接*/
            FD_ZERO(&fdr);
            FD_ZERO(&fdw);
            FD_SET(fd, &fdr);
            FD_SET(fd, &fdw);
            timeout.tv_sec = 10;
            timeout.tv_usec = 0;
            rc = select(fd + 1, &fdr, &fdw, NULL, &timeout);
            printf("rc is: %d\n", rc);
            /*select调用失败*/
            if (rc < 0) {
                fprintf(stderr, "connect error:%s\n", strerror(errno));
                close(fd);
                return -1;
            }

            /*连接超时*/
            if (rc == 0) {
                fprintf(stderr, "Connect timeout.\n");
                close(fd);
                return -1;
            }

            /*[1] 当连接成功建立时,描述符变成可写,rc=1*/
            if (rc == 1 && FD_ISSET(fd, &fdw)) {
                printf("Connect success\n");
                close(fd);
                return 0;
            }

            /*[2] 当连接建立遇到错误时,描述符变为即可读,也可写,rc=2 遇到这种情况,可调用getsockopt函数*/
            if (rc == 2) {
                if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &errlen) == -1) {
                    fprintf(stderr, "getsockopt(SO_ERROR): %s", strerror(errno));
                    close(fd);
                    return -1;
                }

                if (err) {
                    errno = err;
                    fprintf(stderr, "connect error:%s\n", strerror(errno));
                    close(fd);
                    return -1;
                }
            }
        }

        fprintf(stderr, "connect failed, error:%s.\n", strerror(errno));
        return -1;
    }

    return 0;
}

相关文章

  • linux下connect阻塞处理

    主要参考https://www.cnblogs.com/Anker/p/6413642.html 一,问题: 我在...

  • socket

    socket connect阻塞和非阻塞处理 定义信号处理函数

  • 非阻塞connect和accept

    1 非阻塞connect 1.1 阻塞模式与非阻塞 调用connect会发起三次连接。 阻塞模式下,connect...

  • 网络编程&&多线程编程

    非阻塞模式下,send recv connect、accept函数的情况研究 connect阻塞模式下(超时时间7...

  • Android 平台 ndk(linux) socket clo

    遇到一个问题,linux socket 在connect 一个错误的ip地址的情况下,会阻塞,当调用close()...

  • Linux下connect超时处理总结

    1、前言 最近在写一个测试工具,要求快速的高效率的扫描出各个服务器开放了哪些端口。当时想了一下,ping只能检测i...

  • Aspera Connect,高速下载sra数据

    一、下载安装Aspera Connect Linux系统下的Aspera Connect安装(Windows下的A...

  • 2、Linux IO模型

    下图是Linux处理IO调用的流程图: Linux IO模型分为5种: 阻塞IO 非阻塞IO IO复用 事件驱动I...

  • 值1000块的非阻塞CONNECT

    将套接字文件描述符设置成非阻塞之后,对于CONNECT的判定问题。用fcntl将套接字设置为非阻塞。connect...

  • linux五种IO模型

    Linux下主要的IO主要分为:阻塞IO(Blocking IO),非阻塞IO(Non-blocking IO),...

网友评论

      本文标题:linux下connect阻塞处理

      本文链接:https://www.haomeiwen.com/subject/glfeaqtx.html