网络超时检测-11.9

news/2024/5/18 12:36:06 标签: 网络, linux, c语言, IO, tcp/ip, udp, 嵌入式实时数据库
应用场景
  • 网络通信中,很多操作会使得进程阻塞:
    • TCP套接字中的recv/accept
    • UDP套接字中的recvfrom
  • 超时检测的必要性
    • 避免进程在没有数据时无限制地阻塞
    • 实现某些特定协议要求,比如某些设备规定,发送请求数据后,如果多长时间后没有收到来自设备的回复,需要做出一些特殊处理
  1. 自带超时参数的函数

如使用select/poll/epoll函数最后一个参数可以设置超时。

1)select设置超时

struct timeval tm = {2, 0};//设置2s打算阻塞
sret = select(maxfd + 1, &tempfds, NULL, NULL, &tm);
第五个参数:
 struct timeval {
     long    tv_sec;         /*秒*/
     long    tv_usec;        /*微秒*/
 };

2.poll

 int poll(struct pollfd *fds, nfds_t nfds, int timeout);
   第三个参数:时间单位是毫秒 -1阻塞, 2000=2s
   ret = poll(event, num, 2000);//超时检测时间为2s

3.epoll 设置的是epoll_wait


 int epoll_wait(int epfd, struct epoll_event *events,
                      int maxevents, int timeout);
  第四个参数:时间单位是毫秒 -1阻塞, 2000=2s
  ret = epoll_wait(epfd, events, 20, 2000);
设置超时后的返回值都为:<0  error
                        =0   超时
                        >0   正确 

2.利用setsockopt属性设置

Linux中socket属性

选项名称

说明

数据类型

 ====  SOL_SOCKET 应用层  ====

 SO_BROADCAST

       允许发送广播数据

 int

          SO_DEBUG

允许调试

int

SO_DONTROUTE

不查找路由

int

SO_ERROR

获得套接字错误

int

SO_KEEPALIVE

 保持连接

int

SO_LINGER

延迟关闭连接

 struct linger 

SO_OOBINLINE

带外数据放入正常数据流 

int 

SO_RCVBUF

接收缓冲区大小

int

SO_SNDBUF

发送缓冲区大小

int

SO_RCVLOWAT

接收缓冲区下限

int

SO_SNDLOWAT

发送缓冲区下限

 int 

SO_RCVTIMEO

接收超时

struct timeval

SO_SNDTIMEO

发送超时

struct timeval

SO_REUSEADDR

允许重用本地地址和端口

int

SO_TYPE

获得套接字类型

int 

SO_BSDCOMPAT

与BSD系统兼容

                   int

==== IPPROTO_IP  网络层 ====

  IP_HDRINCL

         在数据包中包含IP首部

 int

IP_OPTINOS

 IP首部选项

 int

IP_TOS

服务类型

int

IP_TTL

生存时间

int

IP_ADD_MEMBERSHIP

将指定的IP加入多播组

  struct ip_mreq

==== IPPRO_TCP 传输层 ====

TCP_MAXSEG

TCP最大数据段的大小

int 

TCP_NODELAY

不使用Nagle算法

 int 

功能:设置/获取网络属性;
原型:
       #include <sys/types.h>          /* See NOTES */
       #include <sys/socket.h>

       int getsockopt(int sockfd, int level, int optname,
 void *optval, socklen_t *optlen);
       int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
参数:
    int sockfd:指定要设置/获取哪个套接字的属性;
    int level:指定要控制的协议层次;
        SOL_SOCKET:应用层 通用套接字选项;  man 7 socket
        IPPROTO_TCP:TCP选项               man 7 TCP
        IPPROTO_UDP:UDP选项               man 7 UDP
        IPPROTO_IP:IP选项;                man 7 IP
    int optname:指定要控制的内容,指定控制方式;
      --- SOL_SOCKET: man 7 socket -----
        SO_REUSEADDR:允许端口快速重用   optval: int*
        SO_BROADCAST:允许广播          optval: int*   
        SO_RCVBUF/SO_SNDBUF:接收缓冲区 发送缓冲区大小
        SO_RCVTIMEO/SO_SNDTIMEO:接收超时时间,发送超时时间
    void *optval:根据optname不同,该类型不同;(数据类型
    socklen_t optlen/socklen_t *optlen:真实的optval指针指向的内存空间的大小;
返回值:
    成功,返回0
    失败,返回-1,更新errno;

3、利用alarm定时器设置

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
功能:在进程中设置一个定时器
参数:seconds:定时时间,单位为秒
返回值:如果调用此alarm()前,进程中已经设置了闹钟时间,则
	返回上一个闹钟时间的剩余时间,否则返回0。

alarm(5) 闹钟   定时器
//5秒之后会,会有一个信号产生(SIGALRM)
int sigaction(int signum, const struct sigaction *act,
                     struct sigaction *oldact);
 功能:对接收到的指定信号处理
	signum  信号		 
struct sigaction 
{
    void     (*sa_handler)(int); //信号处理函数
    void     (*sa_sigaction)(int, siginfo_t *, void *);  //信号处理函数
    sigset_t   sa_mask;
    int        sa_flags;      //信号属性; SA_RESTART自重启属性
#define SA_RESTART  0x10000000
    void     (*sa_restorer)(void);
           };     
    //设置信号属性
    struct sigaction act;
    sigaction(SIGALRM,NULL,&act);//获取原属性
    act.sa_handler=handler;//修改属性
    sigaction(SIGALRM,&act,NULL);//将修改的属性设置回去
   
注:在recv前调用alarm函数
   alarm的 SIGALRM信号产生后会打断(终端)下面的系统调用recv;
   打断后相当于recv错误返回。
   信号改变行为后,当前进程所有行为都被改变,若想要再次改变回原行为,需要再次执行sigaction.

注意:一个进程只能有一个闹钟时间。如果在调用alarm时已设置过闹钟时间,则之前的闹钟时间被新值所代替,时间到了会给进程发送一个SIGALRM信号,这个信号也有结束进程的功能

#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void handler(int sig)
{
    printf("timeout................\n");
}

int main(int argc, char const *argv[])
{   
    struct sigaction act;
    sigaction(SIGALRM,NULL,&act);//获取原属性
    act.sa_handler=handler;//修改属性
    sigaction(SIGALRM,&act,NULL);//将修改的属性设置回去

    // sigaction(int signum, const struct sigaction *act,struct sigaction *oldact);
    char buf[64]={};
    while (1)
    {   
        alarm(2);
        printf("hello\n");
        fgets(buf,sizeof(buf),stdin);
        printf("fgets阻塞接触\n");
        int ret=alarm(2);
        printf("%d\n",ret);
        read(0,buf,sizeof(buf));
        printf("read阻塞接触\n");
        printf("buf:%s\n",buf);
    }
    
    return 0;
}


http://www.niftyadmin.cn/n/5183212.html

相关文章

sql统计某列数据出现最多的一个id

SELECT column_name, COUNT(column_name) AS occurrence_count FROM your_table GROUP BY column_name ORDER BY occurrence_count DESC LIMIT 1; 用来展示

利用Nextcloud搭建企业私有云盘系统

利用Nextcloud搭建企业私有云盘系统 1. 场景介绍2. 环境准备3. 安装NextCloud4. 系统功能验证 1. 场景介绍 Nextcloud是一款免费开源的私有云存储系统&#xff0c;采用PHPMySQL开发&#xff0c;提供了多个同步客户端支持多种设备访问&#xff0c;使用Nextcloud可以快速便捷地搭…

【luckfox】3、计算重量差

前言 本章结合之前的hx711驱动&#xff0c;实现读取质量&#xff0c;记录时间及剩余质量并存入csv文件&#xff0c;计算质量差并总计。 代码 luckfox-pico\project\app\test_app\hx711\hx711_app_addtime.c #include <stdio.h> #include <stdlib.h> #include &…

chatGPT真的会改变我们的生活吗?

先不说生活影响有多大&#xff0c;工作职场影响很大&#xff0c;现在在职场&#xff0c;随处可见Chat GPT的身影 OpenAI 开发的 ChatGPT 和类似的人工智能工具在短时间内不会取代我们的工作。但是&#xff0c;在科技、媒体等许多行业中&#xff0c;它们可以帮助员工更好、更快地…

ubuntu设置脚本开机自启动

rc-local.service flexmitd1:~$ cd /lib/systemd/system/ flexmitd1:/lib/systemd/system$ ls |grep rc-local.service rc-local.service rc-local.service.d flexmitd1:/lib/systemd/system$ pwd /lib/systemd/system flexmitd1:/lib/systemd/system$确保有rc-local.service文…

PDF自动打印

​ 最近接到用户提过来的需求&#xff0c;需要一个能够自动打印图纸的功能&#xff0c;经过几天的研究整出来个初版了的&#xff0c;分享出来给大家&#xff0c;希望能有帮助。 需求描述: ​ 生产车间现场每天都有大量的图纸需要打印&#xff0c;一个一个打印太慢了&#xff0…

软件测试个人求职简历该怎么写,模板在这里

1、个人资料 姓 名&#xff1a;xxx 性 别&#xff1a;x 手机号码&#xff1a;138888888xx 邮 箱&#xff1a; xxx 学 历&#xff1a;本科 专 业&#xff1a;电子商务 英 语&#xff1a;四级 当前工作&#xff1a;测试工程师 从业时间&#xff1a;4年 期望薪资&#xff1a;…

GDB符号表概念及Linux获取符号表的方式

GDB符号表概念 GDB符号表是GDB调试器在调试过程中使用的一种数据结构&#xff0c;它包含了程序中函数、变量、类型等信息&#xff0c;方便在GDB在调试过程中进行符号解析和地址定位。 GDB符号表主要由以下几部分组成&#xff1a; 函数符号表&#xff1a;包含了程序中定义的函…