网络编程(五)

网络编程(五)

  • 网络服务器超时检测
    • 使用select进行超时检测
    • 套接字属性
      • **getsockopt:获取socket软通道的某项属性值**
      • setsockopt:设置socket软通道的某项属性值**(socket建立之后就可使用)
    • 信号
      • **signal():信号处理函数===set**
      • **sigaction():信号处理函数===set/get**

网络服务器超时检测

在网络通信中,很多操作会使得进程阻塞
TCP套接字中的recv/accept/connect
UDP套接字中的recvfrom
超时检测的必要性:
1、避免进程在没有数据时无限制地阻塞
2、当设定的时间到时,进程从原操作返回继续运行

使用select进行超时检测

如果该服务器使用select实现的,可以使用select的最后一个参数做超时检测

#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
int select(int nfds, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);
//参数1:需要监控的最大文件描述符的个数,总数
//参数2:指针指向读文件描述符集合表
//参数3:指针指向写文件描述符集合表
//参数4:指针指向异常文件描述符集合表
//参数5:① ② ③
//①NULL—>将select变成阻塞函数
//②0—>仅仅检测文件描述符的状态,然后立即返回,不会置位
//③时间值—>表示select的监控超时时间。时间到达之前select监控到有IO通道活跃,select返回通道路数并置位;超时时间到,select没有监控到任何IO通道有数据,那么select返回0
//返回值:成功返回监控到的有数据发生的通道个数;没有活跃则没有返回,则一直阻塞,失败返回-1

*第四个参数struct timeval timeout
在这里插入图片描述
在这里插入图片描述

套接字属性

socket—>有socket层,IP层,tcp/udp层属性

getsockopt:获取socket软通道的某项属性值

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int getsockopt(int sockfd, int level, int optname,void *optval, socklen_t *optlen);
//参数1:文件描述符–>标识一个网络软通道
//参数2:level指定控制套接字的层次(SOL_SOCKET,IPPROTO_TCP,IPPROTO_IP)
//参数3:要设置的属性项,根据参数2决定属性项
//参数4:参数3对应的属性值的指针
//参数5:指向参数4大小的指针

setsockopt:设置socket软通道的某项属性值**(socket建立之后就可使用)

#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
int setsockopt(int sockfd, int level, int optname,const void *optval, socklen_t optlen);
//参数1:文件描述符–>标识一个网络软通道
//参数2:level指定控制套接字的层次(SOL_SOCKET,IPPROTO_TCP,IPPROTO_IP)
//参数3:要设置的属性项,根据参数2决定属性项
//参数4:参数3对应的属性值的指针
//参数5:指向参数4大小
//返回值:成功返回0,失败返回-1,并更新errno

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//超时检测发送方代码
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
int main(int argc, const char *argv[])
{//1,创建套接字int socketFd = socket(AF_INET, SOCK_DGRAM, 0);if(socketFd < 0){perror("socket udp client error");return -1;}printf("socket udp client ok!\n");//2,设置服务器的IP 地址和端口struct sockaddr_in addr;bzero(&addr, sizeof(addr));//赋值addr.sin_family = AF_INET;addr.sin_port = htons(8888);//接收方的端口addr.sin_addr.s_addr = inet_addr("224.0.2.88");//组播地址//允许组播int opt = 1;setsockopt(socketFd, IPPROTO_IP, IP_MULTICAST_IF, &opt, sizeof(opt));//3,通信char buf[256] = {0};while(1){bzero(buf, sizeof(buf));printf("推送一条组播消息:");fgets(buf, sizeof(buf), stdin);//从标准输入流中获取数据if(0 == strncasecmp("quit", buf, 4)){printf("结束!\n");bzero(buf, sizeof(buf));sendto(socketFd, buf, strlen(buf), 0, \(struct sockaddr *)&addr, sizeof(addr));break;}//发送消息sendto(socketFd, buf, strlen(buf), 0, \(struct sockaddr *)&addr, sizeof(addr));printf("send multicast message ok!\n");}//关闭套接字close(socketFd);return 0;
}
//超时检测接收方代码
recvfrom进行超时检测
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
int main(int argc, const char *argv[])
{//1,创建套接字int socketFd = socket(AF_INET, SOCK_DGRAM, 0);printf("socket server ok!\n");//2,绑定接收方的IP 地址和端口struct sockaddr_in addr;bzero(&addr,sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(8888);//指定的接收方端口,必须和发送方一样addr.sin_addr.s_addr = htonl(INADDR_ANY);//任意地址bind(socketFd, (struct sockaddr *)&addr, sizeof(addr));printf("bind ok!\n");//3,加入到多播组中struct ip_mreq ipaddr;bzero(&ipaddr, sizeof(ipaddr));ipaddr.imr_multiaddr.s_addr = inet_addr("224.0.2.88");ipaddr.imr_interface.s_addr = htonl(INADDR_ANY);setsockopt(socketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipaddr,sizeof(ipaddr));char buf[256] = {0};//4,接收多播组中的消息//定义存储对方地址信息的结构变量struct sockaddr_in otherAddr;bzero(&otherAddr, sizeof(otherAddr));int len = sizeof(otherAddr);while(1){bzero(buf, sizeof(buf));//设置超时检测struct timeval timeout;bzero(&timeout, sizeof(timeout));timeout.tv_sec = 3;//设置setsockopt(socketFd, SOL_SOCKET, SO_RCVTIMEO,&timeout,sizeof(timeout));//注意:udp服务器一定要存储发送方的地址信息(没有建立过连接,每一次//的发送,都需要知道对方的地址信息!!!)int ret = recvfrom(socketFd, buf, sizeof(buf), 0, \(struct sockaddr *)&otherAddr, &len);if(ret < 0){//判断错误码是否为EAGAINif(errno == EAGAIN){printf("已超时3秒...");}else{perror("recvfrom error");break;}}else if(0 == ret){printf("组中停止消息的发送~\n");break;}else{printf("接收的组播消息:%s\n",buf);}}//5,离开多播组setsockopt(socketFd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipaddr,sizeof(ipaddr));//6,关闭套接字close(socketFd);return 0;
}

信号

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//信号处理函数:
void handler_func(int signum)
{
;
}
//信号行为结构体
struct sigaction {
void (*sa_handler)(int);//信号处理函数,和signal一样的
void (*sa_sigaction)(int, siginfo_t *, void *);
sigset_t sa_mask;
int sa_flags;//标志,可以设置为取消自重启属性
void (*sa_restorer)(void);
};

更改信号默认操作:

signal():信号处理函数===set

signal函数原型:
#include <signal.h>
void (*signal(int signum, void (*handler)(int)))(int);
优化原型:看的更清楚。
//给函数指针类型取别名
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

功能:进行信号安装
参数:
参数1:需要安装的信号名称
参数2:对于该信号的处理函数(该函数是用户自定义的,且返回值类型void ,形参是一个int的函数的地址)
PS:参数2的位置可以传入:忽略(SIG_IGN) 执行缺省操作(SIG_DFL),信号处理函数的地址
返回值:成功安装完毕的信号处理函数的地址。

sigaction():信号处理函数===set/get

sigaction(信号,处理动作结构,处理动作结构)
① sigaction(SIGALRM, NULL, &act) //获取SIGALRM信号对应的默认处理信息结构
① sigaction(SIGALRM, &act, NULL)//设置SIGALRM信号对应的新的处理信息结构

在这里插入图片描述
在这里插入图片描述

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
//参数:秒数
//当定时器指定的时间到了时,它就向进程发送SIGALARM信号,信号的默认操作是结束进程.
//注意:每个进程只能有一个闹钟时间。如果在调用alarm时,以前已为该进程设置过闹钟时间,而且它还没有超时,则该闹钟时间的剩余时间值作为本次alarm函数调用的值返回,以前登记的闹钟时间则被新值代换。如果有以前登记的尚未超过的闹钟时间,而新设的闹钟时间值为0,则取消以前的闹钟时间,其剩余时间值仍作为函数的返回值。

在这里插入图片描述
在这里插入图片描述

//alarm定时器接收方超时检测代码
#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <strings.h>
#include <string.h>
#include <netinet/in.h>
#include <errno.h>
#include <signal.h>
//信号处理函数
void handler_func(int signum)
{printf("已超时...\n");
}
int main(int argc, const char *argv[])
{//1,创建套接字int socketFd = socket(AF_INET, SOCK_DGRAM, 0);printf("socket server ok!\n");//2,绑定接收方的IP 地址和端口struct sockaddr_in addr;bzero(&addr,sizeof(addr));addr.sin_family = AF_INET;addr.sin_port = htons(8888);//指定的接收方端口,必须和发送方一样addr.sin_addr.s_addr = htonl(INADDR_ANY);//任意地址bind(socketFd, (struct sockaddr *)&addr, sizeof(addr));printf("bind ok!\n");//3,加入到多播组中struct ip_mreq ipaddr;bzero(&ipaddr, sizeof(ipaddr));ipaddr.imr_multiaddr.s_addr = inet_addr("224.0.2.88");ipaddr.imr_interface.s_addr = htonl(INADDR_ANY);setsockopt(socketFd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &ipaddr,sizeof(ipaddr));char buf[256] = {0};//4,接收多播组中的消息//定义存储对方地址信息的结构变量struct sockaddr_in otherAddr;bzero(&otherAddr, sizeof(otherAddr));int len = sizeof(otherAddr);//第一步:先获取SIGALRM信号的旧行为struct sigaction act;bzero(&act, sizeof(act));sigaction(SIGALRM, NULL, &act);//第二步:设置处理函数+取消recvfrom的自重启属性act.sa_handler = &handler_func;//act.sa_flags |= SA_RESTART;//启动函数的自重启属性:eg:recvfrom:自重启属性再次陷入阻塞act.sa_flags &= ~SA_RESTART;//取消recvfrom再次陷入阻塞//第三步:将设置完毕的新行为设置给SIGALRM信号sigaction(SIGALRM, &act, NULL);while(1){bzero(buf, sizeof(buf));//使用sigaction函数捕捉SIGALRM信号,给他设置一个处理函数和//取消recv函数自带的自重启属性//设置超时检测alarm(5);//秒到了,会产生SIGALRM信号//注意:udp服务器一定要存储发送方的地址信息(没有建立过连接,每一次//的发送,都需要知道对方的地址信息!!!)int ret = recvfrom(socketFd, buf, sizeof(buf), 0, \(struct sockaddr *)&otherAddr, &len);if(ret < 0){perror("recvfrom error");//perror:interrupt syatem call-->中断系统调用//break;加了break此时会直接跳出while循环,不加则继续进行等待接收(超时检测)}else if(0 == ret){printf("组中停止消息的发送~\n");break;}else{printf("接收的组播消息:%s\n",buf);}}//5,离开多播组setsockopt(socketFd, IPPROTO_IP, IP_DROP_MEMBERSHIP, &ipaddr,sizeof(ipaddr));//6,关闭套接字close(socketFd);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/21385.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Android11 AudioTrack 创建过程

Android 系统播放声音&#xff0c;需要创建AudioTrack来和AudioFlinger通信&#xff0c;其创建过程如下 根据传入的声音属性得到output通过得到的output&#xff0c;找到播放线程AudioFlinger在播放线程内&#xff0c;创建Track&#xff0c;和AudioTrack对应。后续通过它们进…

MiniQMT国债逆回购策略Python代码全解析

文章目录 💼 国债逆回购:稳赚不赔的秘密武器📈 国债逆回购基础知识📝 国债逆回购策略逻辑💻 Python代码实现📊 策略优化与风险管理🌐 结语💼 国债逆回购:稳赚不赔的秘密武器 国债逆回购,一种低风险、高流动性的投资方式,是股市小白向高手进阶的必经之路。本…

每天一个数据分析题(三百四十五)

客户生命周期主要分为新增、留存和流失三个阶段&#xff0c;以下描述正确的是&#xff1f; A. 客户生命周期有起点没有终点 B. 新增阶段主要描述商家从不同渠道获取的新增客户的数量及质量 C. 留存阶段是整个客户生命周期中时间跨度最长的阶段 D. 若客户在单位时间内没有触…

低代码设计中的组织结构的作用与模式

一、组织结构的作用 在低代码设计中&#xff0c;组织结构是系统运作的基石&#xff0c;它定义了系统中的关键元素&#xff0c;包括人员、部门、角色&#xff0c;以及一人多部门、一人多部门多角色的复杂关系。这种定义不仅为系统提供了清晰的运行框架&#xff0c;还确保了系统…

这是一张单纯的图片

说明&#xff1a;通过简单的一张图片找到flag。 打开给出的图片&#xff0c;是一个卡通头像。 方法一&#xff1a; 使用notepad再次打开图片&#xff0c;最后一行发现一行编码。 通过给出的编码格式&#xff0c;可判断是ASCII编码。 使用Ascii编码解码工具&#xff0c;对这串…

解决uniApp单独设置小程序的样式不起作用方法之一

问题点&#xff1a;在uniApp项目中单独设置了微信小程序员端的样式&#xff0c;结果发现设置的不起作用 原因&#xff1a;作用域的问题&#xff08;因为我设置了scoped&#xff0c;删除掉就好了&#xff09; /**我是这么设置的**/ <style scoped>/* #ifdef MP-WEIXIN */p…

贾英才医生:什么是脑白质病?如何预防此病?

贾英才医生&#xff0c;目前就任于北京崇文门中医医院&#xff0c;作为在医学领域有着深厚造诣和丰富经验的专业人士&#xff0c;在此深入探讨和剖析这样一个重要的医学话题&#xff1a;究竟什么是脑白质病&#xff1f;以及我们应该采取怎样切实可行的措施来有效预防此种疾病的…

前端框架原理自测题:根据 JSX / Vue 模板写出 render 函数 / VNode

JSX <div className"container"><p onClick{onClick} data-name"p1">hello <b>{name}</b></p><img src{imgSrc}/><MyComponent title{title}></MyComponent> </div>Vue 模板 <div class"co…

pip原理及常用命令

1、pip帮助文档 pip documentation 2、pip命令帮助 pip --help 或 pip 3、常用命令 pip install SomePackage # 最新版本 pip install SomePackage1.0.4 # 指定版本 pip install SomePackage>1.0.4 # 最小版本 pip install -i https://pypi.do…

计算机设备管理器端口不见了怎么办?

因为重装了系统&#xff0c;一切都得重新配置&#xff0c;但突然发现计算机资源设备里面端口这一选项居然不见了&#xff0c;这对一个嵌入式工程师是致命的&#xff0c;赶紧想想怎么处理 1、在电脑左下角windows右键&#xff0c;打开从上往下数第六个“资源管理器” 2、端口没…

Chrome 调试技巧

1. alert 在最早的时候&#xff0c;javascript 程序员调试代码都是通过 alert 进行&#xff0c;但 alert 会让整个程序被打断&#xff0c;并且还有一个很大的缺点&#xff0c;调试完成之后&#xff0c;如果忘记将 alert 删除 or 注释掉&#xff0c;导致别人访问该页面时会莫名…

迅狐短剧小程序源码:打造个性化的追剧体验

随着移动互联网的普及&#xff0c;短剧小程序源码的开发成为了影视爱好者的新宠。它不仅为用户提供了便捷的追剧体验&#xff0c;还通过推荐系统、观看历史、个性化喜好等特色功能&#xff0c;满足了用户的多样化需求。本文将深入探讨短剧小程序源码的特点、优势以及如何实现多…

创新指南|领导者如何评估自己的表现——麦肯锡专有的CEO卓越评估工具

CEO是任何组织中最具挑战性和要求最高的职位之一&#xff0c;尤其是在当前的经济环境下。这也是最重要的职位之一。研究表明&#xff0c;一家公司 45% 的业绩可归因于CEO的影响。但 CEO 们的实际表现如何&#xff1f;他们面临哪些问题&#xff1f;如何帮助他们发挥出最佳水平&a…

Java中的泛型类型参数详解

Java中的泛型机制为开发者提供了一种编写通用代码的强大工具&#xff0c;使得代码在编译时可以进行类型检查&#xff0c;从而减少运行时的错误。泛型类型参数可以帮助我们编写更加灵活和类型安全的代码。在Java的泛型类型参数中&#xff0c;我们经常会看到一些常见的符号&#…

代碼隨想录 day22|day23

二叉树(完) 二叉搜索树的最近公共祖先 题意&#xff1a;找到二叉树的两个节点的祖先节点 。 思路&#xff1a; 二叉树的中序遍历特性&#xff1a; 如果当前遍历的节点的值> 两个指定的节点的值。 那么祖先节点就在当前节点左子树 。 如果当前遍历节点的值< 两个节点的值…

赶紧收藏!2024 年最常见 20道 Kafka面试题(四)

上一篇地址&#xff1a;赶紧收藏&#xff01;2024 年最常见 20道 Kafka面试题&#xff08;三&#xff09;-CSDN博客 七、Kafka数据一致性原理是什么&#xff1f; Kafka的数据一致性原理主要依赖于其内部的复制机制、分区策略、领导者与追随者&#xff08;Leader and Follower…

java-成员变量和局部变量

Java中的变量根据其作用域和生命周期可以分为两大类&#xff1a;成员变量&#xff08;Instance Variables&#xff09;和局部变量&#xff08;Local Variables&#xff09;。这两类变量在Java程序中扮演着重要的角色&#xff0c;它们用于存储程序运行时所需的数据。 一、成员变…

贝锐向日葵分组策略:减少重复操作,提升管理效率

面对大数量级的IT设备&#xff0c;如何高效实施管理是运维的关键所在&#xff0c;如何快速准确的对大量的设备按需分组&#xff0c;则是管理精准触达的第一步。 但是&#xff0c;传统的分组方式应付少量设备还可行&#xff0c;设备数量级一旦来到上千台甚至更多时&#xff0c;…

【分红+估值修复】人工智能选股策略》?

今天公告中的部分内容上次去兴业交流的时候跟管理层也聊到了&#xff0c;比如分红、大股东增持、六大新赛道等。 我一直呼吁的管理层增持这次也体现在公告中。 这都体现了上市公司对于维护公司股价和合理估值的重视&#xff0c;对于股东合理投资回报的重视。 对于上市公司而言&…

linux安装docker步骤

步骤1 脚本自动安装 curl -fsSL https://get.docker.com -o get-docker.sh sudo sh get-docker.sh 步骤2 启动Docker服务: sudo systemctl start docker 步骤3 验证Docker是否正确安装并运行一个容器: sudo docker run hello-world 安装正确&#xff0c;则可拉取镜像&am…