connect()函数阻塞问题解决

2019-07-13 07:16发布

1.采用select 在学习嵌入式Linux网络编程中,很多同学都发现了一个问题,那就是调用connect函数时,如果服务端关闭,客户 端调用connect()函数时,发现阻塞在那里,而且利用ctrl+c信号去停止客户端程序时,需要等待一个较为长的时间才能响应了,这个时间如果大家 细心会发现,每次都是75秒的时间。那么有没有什么比较好的办法,可以以用户能接受的一个时间响应来停止掉一个正在connect连接的客户端那?比如我 们在做一个网络控制台的程序,用户需要随时可以停止掉任何一个网络服务连接,那么对于这样一个需要等待75秒时间才能反馈出服务状态的程序,用户是无法接 受的。 对于如何解决这个问题,我们可以分析下,要想完成用户在一个能接受的时间里迅速反馈出服务 端已经关闭的状态,那么我们的程序应该做到在一个规定的时间片内,可以捕获到用户发出的控制状态,然后处理用户的需求。那么要做到可以在规定的时间片内捕 获用户的控制状态,就必须禁止让我们的connect()函数阻塞75秒的情况发生,也就是说,要让connect()函数变为非阻塞状态才行。 好了,现在解决问题的关键就是如何把connect变为非阻塞状态了,我们知道,socket编程的操作对象是socket,而socket他又属于系统描述符类型,那么对于系统描述符,我们是怎么操作他变为非阻塞的那?是利用fcntl()函数或者ioctl()函数。 想到这里,好像问题应该已经解决了,但是我们调试发现,在服务端出现错误的时候,connect确实马上返回,但是,如果服务端正确那,connect还是马上返回,这样,我们无法判断connect函数是否成功了,那这个问题又该如何解决呢? 我们是否想到了一个select函数那,他具备监听文件描述符的功能,如果我们把之前的socket让select监听他是否可写,是不是问题也就解决了。 好了,那么我们总结下整个思路: 1.建立socket
        2.将该socket设置为非阻塞模式
        3.调用connect()
        4.使用select()检查该socket描述符是否可写
        5.根据select()返回的结果判断connect()结果
        6.将socket设置为阻塞模式 对于第六步,为什么还要设置为阻塞模式那,留给我们同学自己思考下。 那么根据上面的6个步骤,我们写一个简单的模块程序来调试看下: {
                int sockfd = socket(AF_INET, SOCK_STREAM, 0);
                if(sockfd < 0) exit(1);
                struct sockaddr_in serv_addr;
                ………//以服务器地址填充结构serv_addr
                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_set = TIME_OUT_TIME;