方法一:采用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;

                        tm.tv_uset
= 0;

                        FD_ZERO(&set);

                        FD_SET(sockfd,
&set);

                        if(
select(sockfd+1, NULL, &set, NULL, &tm) > 0)

                        {

                                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); //设置为阻塞模式

                //下面还可以进行发包收包操作

                ……………

        }

方法二:定义信号处理函数

  1. sigset(SIGALRM, u_alarm_handler);
  2. alarm(2);
  3. code = connect(socket_fd, (struct
    sockaddr*)&socket_st, sizeof(struct
    sockaddr_in));
  4. alarm(0);
  5. sigrelse(SIGALRM);

首先定义一个中断信号处理函数u_alarm_handler,用于超时后的报警处理,然后定义一个2秒的定时器,执行connect,当系统
connect成功,则系统正常执行下去;如果connect不成功阻塞在这里,则超过定义的2秒后,系统会产生一个信号,触发执行 u_alarm_handler函数, 当执行完u_alarm_handler后,程序将继续从connect的下面一行执行下去。

     其中,处理函数可以如下定义,也可以加入更多的错误处理。

  1. void u_alarm_handler()
  2. {
  3. }

connect()函数阻塞问题的更多相关文章

  1. 【网络编程】——connect函数遇见EINTR的处理

    最近在公司项目中突然报错如下 “connect: Interrupted system call”, 经过查找代码发现是在创建 socket 中执行了 connect 函数失败导致.上网查阅资料发现这 ...

  2. 【QT】跨线程的信号槽(connect函数)

    线程的信号槽机制需要开启线程的事件循环机制,即调用QThread::exec()函数开启线程的事件循环. Qt信号-槽连接函数原型如下: bool QObject::connect ( const Q ...

  3. UDP的connect函数

    UDP的connect没有三次握手过程,内核只是检测是否存在立即可知的错误(如一个显然不可达的目的地), 记录对端的的IP地址和端口号,然后立即返回调用进程. 未连接UDP套接字(unconnecte ...

  4. connect函数详解

    不得不说,客户端的connect函数和服务端的accept函数是一对好基友,如果客户端没有去connect, 那么服务端的accept会一直在那里傻傻地痴痴地等待,我们先来看看connect函数的原型 ...

  5. QT QObject::connect函数的学习

      从Qobject(QObject.h)源码中可以看到QObject::connect的定义是这样的: static bool connect(const QObject *sender, cons ...

  6. connect函数

    TCP客户用connect函数来建立与TCP服务器的连接 int connect (int sockfd, const sockaddr * servaddr, socklen_t addrlen); ...

  7. connect函数的用法

    无论流式套接字(如TCP)还是数据报(如UDP),均可以使用connect函数.对于流式套接字,使用connect函数后,建立固定地址的连接,之后可以使用send/rev函数进行数据收发.对于数据报, ...

  8. 关于react-redux中的connect函数

    示例代码 'use strict'; import React from 'react'; import { connect } from 'react-redux'; class demo exte ...

  9. Windows编程之connect函数研究

    写在前面:本博客为本人原创,严禁任何形式的转载!本博客只允许放在博客园(.cnblogs.com),如果您在其他网站看到这篇博文,请通过下面这个唯一的合法链接转到原文! 本博客全网唯一合法URL:ht ...

随机推荐

  1. 企业如何通过CRM系统使销售周期缩短

    企业为什么要缩短销售周期?因为这意味着可以节约更多开支,从而达到企业利润最大化.但是有不少企业尤其是B2B行业,销售周期都在三个月以上.通过调查发现,很多企业在客户信息和销售管道上缺乏管理和策略.Zo ...

  2. 为什么要鼓励小型企业使用CRM系统

    如果你是一家小公司的管理者,我相信你必须对工作流程.客户.市场销售.市场营销推广等业务流程进行总体规划和管理方法,这往往会使你的心有馀而力不足,引起 繁忙.心有馀而力不足.交流受到阻碍.管理方法和这样 ...

  3. Linux:Ubuntu银河麒麟防火墙操作

    查看防火墙状态 #防火墙状态 sudo ufw status inactive状态是防火墙 关闭 状态 active状态是防火墙 开启 状态 开启防火墙 #开启防火墙 sudo ufw enable ...

  4. 1.3.2、通过Cookie匹配

    server: port: 8080 spring: application: name: gateway cloud: gateway: routes: - id: guo-system4 uri: ...

  5. mysql大量数据分页查询优化-延迟关联

    所有的php初学者都应该知道,mysql的分页语句写法如下: 1 select * from a limit (page-1)*page_size,page_size 而当这语句分页到一定程度时,例如 ...

  6. get和post两种表单提交方式的区别

    今天看到一篇博客谈论get和post区别,简单总结一下https://www.cnblogs.com/logsharing/p/8448446.html 要说两者的区别,接触过web开发的人基本上都能 ...

  7. WPF教程十一:简单了解并使用控件模板

    WPF教程十一:简单了解并使用控件模板 这一章梳理控件模板,每个WPF控件都设计成无外观的,但是行为设计上是不允许改变的,比如使用Button的控件时,按钮提供了能被点击的内容,那么自由的改变控件外观 ...

  8. FreeRTOS基本概念

    1.在FreeRTOS中,使用的数据类型虽然都是标准C里面的数据类型,但是针对不同的处理器,对标准C的数据类型又进行了重新定义. 2.链表由节点组成,节点与节点之间首尾相连,节点包含用于指向后一个节点 ...

  9. RabbitMQ入门教程 [转]

    1.引言 RabbitMQ--Rabbit Message Queue的简写,但不能仅仅理解其为消息队列,消息代理更合适.消息队列主要解决应用耦合,异步消息,流量削锋等问题.实现高性能,高可用,可伸缩 ...

  10. 史上最全的Nginx配置文档

    Nginx是一个异步框架的Web服务器,也可以用作反向代理,负载平衡器 和 HTTP缓存.该软件由Igor Sysoev 创建,并于2004年首次公开发布.同名公司成立于2011年,以提供支持.Ngi ...