TCP/IP Connect时间自主设定

       最近遇到我负责的控制系统作为客户端,而远端的UI作为服务器,在启动的时候,如果服务器端启动延迟了,客户端connect会卡2-3分钟,这个不是很好,需要优化,要求30s内完成,查看了很多资料,发现connect很任性,没有timeout参数可以设置,而且他的timeout时间完全是有系统控制的。因此网上求助各路大神的文章,得到下面的一个比价好的办法,因此整理一下,留作自己备份,也供其他朋友借鉴(很多思路是借鉴别人的,但是还是写为自己原创的,如有剽窃,请见谅)

        网络编程中socket大家都很清楚了,socket也就是套接口,在套接口编程中,提到超时的概念,我们一下子就能想到3个:发送超时,接收超时,以及select超时(注:select函数并不是只用于套接口的,但是套接口编程中用的比较多),在connect到目标主机的时候,这个超时是不由我们来设置的。不过正常情况下这个超时都很长,并且connect又是一个阻塞方法,一个主机不能连接,等着connect返回还能忍受,你的程序要是要试图连接多个主机,恐怕遇到多个不能连接的主机的时候,会塞得你受不了的。本文是已在Linux下的程序为例子,不过拿到Windows中方法也是一样,无非是换几个函数名字罢了。

1.首先调用ioctl将标志位设为Non-blocking模式,准备在非阻塞模式下调用connect函数

2.调用connect,因为TCP三次握手需要一些时间,而非阻塞情况下只要不能立即完成连接就会立即返回错误,所以这里会返EINPROGRESS,表示在建立连接但还没有完成。

3.在读套接口描述符集(fd_set rset)和写套接口描述符集(fd_set wset)中将当前套接口置位(用FD_ZERO()、FD_SET()宏),并设置好超时时间(struct timeval *timeout)

4.调用select( socket, &rset, &wset, NULL, timeout )返回0表示connect超时

如果你设置的超时时间大于75秒(据调查大部分系统都是这个timeout时间)就没有必要这样做了,因为内核中对connect有超时限制就是75秒。
Linux中要给connect设置超时,应该是有两种方法的。一种是该系统的一些参数,这个方法我不讲,因为我讲不清楚:P,它也不是编程实现的。另外一种方法就是变相的实现connect的超时,我要讲的就是这个方法,原理上是这样的:
1.建立socket
2.将该socket设置为非阻塞模式
3.调用connect()
4.使用select()检查该socket描述符是否可写(注意,是可写)
5.根据select()返回的结果判断connect()结果
6.将socket设置为阻塞模式(如果你的程序不需要用阻塞模式的,这步就省了,不过一般情况下都是用阻塞模式的,这样也容易管理)

#include 
#include 
#include 
#define TIME_OUT_TIME 30
int connect_with_cust_timeout(int sockfd) {
    int error=-1, len;
    len = sizeof(int);
    timeval tm;
    fd_set set;
    unsigned long ul = 1;
    ioctl(sockfd, FIONBIO, &ul); //设置为非阻塞模式
    bool ret = false;
    if( connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) == -1) {
        tm.tv_sec = TIME_OUT_TIME;   //设置timeout时间30s
        tm.tv_usec = 0;
        FD_ZERO(&set);
        FD_SET(sockfd, &set);
        if(select(sockfd+1, NULL, &set, NULL, &tm) > 0)
        {
            //返回当前sockfd错误状态,即SO_ERROR
            getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &error, (socklen_t *)&len);
            if(error == 0)
                ret = true;
            else
                ret = false;
        } else
            ret = false;
    } else {
        ret = true;
    }
    ul = 0;
    ioctl(sockfd, FIONBIO, &ul); //设置为阻塞模式
    return ret;
}

 

 

 

 

 









 

你可能感兴趣的:(TCP/IP Connect时间自主设定)