网络超时检测-11.9

应用场景

  • 在网络通信中,很多操作会使得进程阻塞:
    • 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;`
`}`

`
相关推荐
皓月盈江15 分钟前
Linux Debian安装ClamAV和命令行扫描病毒方法,以及用Linux Shell编写了一个批量扫描病毒的脚本
linux·运维·ubuntu·debian·clamav·开源杀毒
steveqobs21 分钟前
Debian-linux运维-locale配置(locale failed)
linux·运维·debian
万亿少女的梦16830 分钟前
高校网络安全存在的问题与对策研究
java·开发语言·前端·网络·数据库·python
叫我阿呆就好了44 分钟前
C 进阶 — 文件操作
c语言·开发语言
m0_748239331 小时前
Linux下C++轻量级WebServer服务器 框架梳理
linux·服务器·c++
阳光开朗大男孩 = ̄ω ̄=1 小时前
指针之矢:C 语言内存幽境的精准飞梭
c语言
Michael_Good1 小时前
【C/C++】C语言编程规范
c语言·开发语言·c++
R-sz1 小时前
解决k8s部署dashboard时一直处于Pending状态的问题
linux·容器·kubernetes
hao_wujing2 小时前
云计算时代携程的网络架构变迁
网络·架构·云计算
2301_815389372 小时前
【笔记】在虚拟机中通过apache2给一个主机上配置多个web服务器
linux·服务器·笔记