网络编程(五)

网络编程(五)

  • 网络服务器超时检测
    • 使用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)
		{
			//判断错误码是否为EAGAIN
			if(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.mfbz.cn/a/674975.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

34. 【Java教程】反射

本小节我们来学习一个 Java 语言中较为深入的概念 —— 反射&#xff08;reflection&#xff09;&#xff0c;很多小伙伴即便参与了工作&#xff0c;可能也极少用到 Java 反射机制&#xff0c;但是如果你想要开发一个 web 框架&#xff0c;反射是不可或缺的知识点。本小节我们将…

天诚学校物联网锁、公租房智能门锁亮相2024永康门博会

5月26-28日&#xff0c;全场景AIoT解决方案服务商——江苏新巢天诚智能技术有限公司&#xff08;以下简称“天诚”&#xff09;盛装出席第14届中国&#xff08;永康&#xff09;国际门业博览会&#xff08;以下简称“门博会”&#xff09;。 门博会亮点十足 作为享誉海内外的…

产品评测:Coolmuster Android Eraser - 安全彻底删除Android数据的利器

产品概述 在数字化时代&#xff0c;智能手机成为了个人敏感信息的集中地。当涉及到数据隐私和安全时&#xff0c;简单的删除操作并不能满足我们对数据彻底清除的需求。Coolmuster Android Eraser正是为了解决这一问题而生&#xff0c;它是一款专为Android设备设计的第三方软件&…

VUE封装-自定义权限控制指令

在实际开发中&#xff0c;会遇到很多的权限控制、资源位的场景&#xff0c;其实就是用来控制某个组件的展示与否&#xff0c;可以是一个按钮、一个报表、一个TAB页面等 例如下图&#xff0c;我想通过当前登录的用户控制谷歌的这个logo显示与否 因为设计到的权限、资源位控制比…

图片中线段和圆圈检测(python opencv)

前言 本文实现将一个图片中的线段和圆圈检测出来&#xff0c;效果就像这样 开始之前请先自行安装 opencv 另外还用到了一个用来检测直线&#xff1a; http://olena.pages.lre.epita.fr/pylena/index.html pip install pylena直线检测 先用 opencv 来检测直线, 因为下面代码…

天融信 2023 的年终奖。。

天融信 过去几天&#xff0c;最大的瓜&#xff0c;是天融信 2023 的年终奖脚踝砍。 "天融信"是国内首家网络安全企业&#xff0c;同时也是一家上市公司。 就在前些天&#xff0c;有网友爆料出&#xff0c;天融信年终奖到账只有几百元&#xff0c;甚至只有几十元&…

铝包木门窗性能优异 国内产量及需求量总体呈增长态势

铝包木门窗性能优异 国内产量及需求量总体呈增长态势 铝包木门窗是在保留纯实木门窗特性和功能的前提下&#xff0c;将隔热断桥铝合金型材和实木通过机械方法复合而成的框体。铝包木门窗具有良好的密封性、保温性、抗腐蚀性、隔音性等&#xff0c;能够满足市场对门窗质量要求不…

【Linux-阻塞,非阻塞,异步】

Linux-阻塞&#xff0c;非阻塞&#xff0c;异步 ■ Linux-阻塞-非阻塞 IO-异步■ Linux-阻塞IO■ 阻塞IO简介■ open■ 等待队列■ 示例一&#xff1a;APP阻塞IO读取进入睡眠后-等待队列唤醒进程■■ ■ Linux-非阻塞IO■ 非阻塞IO简介■ open■ 轮询■ 1、select 函数■ 2、po…

【轻触按键】开关机电路--填坑1

接上文&#xff0c;挖的坑 一、翻转电路 二、真值表 按键按下去&#xff0c;1G17会拉低&#xff0c;A端脚会掉电&#xff0c;下降沿&#xff1b;终到逻辑“0” 松开按键&#xff0c;1G17会拉高&#xff0c;A端脚充电&#xff0c;上升沿&#xff1b;终到逻辑“1”&#xff1b; …

[补题记录]LeetCode 6.Z字形变换

传送门&#xff1a;Z字形变换 转自&#xff1a;Z字形变换 Thought/思路 关键点在于&#xff0c;最后的答案是一行行连接起来的。 这样我们就会发现&#xff0c;这个 Z 字&#xff0c;实际上会让行数 不断加 1&#xff0c;然后又 不断减 1。每次按顺序选择 S 中的一个字符即…

visual studio打包qt算子时,只生成dll没有生成lib等文件

问题&#xff1a;在visual studio配置了qt项目&#xff0c;并打包成dll&#xff0c;原则上会生成一堆文件&#xff0c;包括dll,lib等文件。 解决办法&#xff1a; 挨个右击源代码的所有头文件-》属性-》项类型。改成qt头文件形式&#xff0c;如下。

961题库 北航计算机 计算机网络 附答案 简答题形式

有题目和答案&#xff0c;没有解析&#xff0c;不懂的题问大模型即可&#xff0c;无偿分享。 第1组 习题 某网络拓扑如题下图所示&#xff0c;其中 R 为路由器&#xff0c;主机 H1&#xff5e;H4 的 IP 地址配置以及 R 的各接口 IP 地址配置如图中所示。现有若干以太网交换机…

C#中使用Mapster

Mapster是一个开源的.NET对象映射库&#xff0c;它提供了一种简单而强大的方式来处理对象之间的映射。 多个映射框架的性能对比&#xff1a; 第一步安装Mapster 使用方法 public class Test {public string name { get; set; }public string sex { get; set; }public string…

光伏并网逆变器UL 1741:2021标准解析

光伏并网逆变器UL 1741:2021标准解析 不同国家的安规认证可以说是光伏逆变器走向国际市场的一张通行证&#xff0c;由于全球各国家的电网制式及并网政策的不同差异&#xff0c;这对逆变器测试顺利的通过安规测试认证 还是有一定的技术难度&#xff0c;也是中国光伏制造企业迫切…

在Linux中tomcat占用内存过高可以通过导出hprof日志来解决

自动导出hprof日志 第一种方法&#xff1a; Tomcat的hprof日志是一种用于分析Java堆内存使用情况的工具&#xff0c;它可以帮助开发人员找到内存泄漏的原因。 hprof日志可以在特定的时间点对Java堆内存进行快照&#xff0c;并生成详细的分析报告。 启用hprof日志导出的具体…

零基础写框架:从零设计一个模块化和自动服务注册框架

模块化和自动服务注册 基于 ASP.NET Core 开发的 Web 框架中&#xff0c;最著名的是 ABP&#xff0c;ABP 主要特点之一开发不同项目(程序集)时&#xff0c;在每个项目中创建一个模块类&#xff0c;程序加载每个程序集中&#xff0c;扫描出所有的模块类&#xff0c;然后通过模块…

“去员工化”这个潮流谁也挡不住,六大诱因分析。

去员工化→恐怕是未来工作的主流&#xff0c;一方面有成本的原因&#xff0c;另一方面也有技术进步、雇佣形式创新等原因&#xff0c;这个潮流有利也有弊&#xff0c;关键看我们是如何兴利除弊。 "去员工化"是指企业在运营中减少或取消传统雇佣制度&#xff0c;更多…

HOW - vscode 使用指南

目录 一、基本介绍1. 安装 VS Code2. 界面介绍3. 扩展和插件4. 设置和自定义 二、常用界面功能和快捷操作&#xff08;重点&#xff09;常用界面功能快捷操作 三、资源和支持 Visual Studio Code&#xff08;VS Code&#xff09;是一款由微软开发的免费、开源的代码编辑器&…

vue开发网站-使用插件element、vant 遇到的问题

1. js把两个字符串放进一个另字符串里&#xff0c;用逗号分隔 let string1 "Hello"; let string2 "World"; let result ${string1},${string2}; console.log(result); // 输出: Hello,World2.js将字符串转为数组 const str "Hello, world!"…

HBuilder中怎样修改每次输出的内容hello?每次修改之后再次“运行到”的时候,怎样保证每次都重新编译?

要修改每次输出的内容&#xff0c;可以在代码中找到输出的地方&#xff0c;并将内容进行修改。例如&#xff0c;在JavaScript中&#xff0c;可以使用console.log()函数输出内容。在修改内容后&#xff0c;保存代码。 为了保证每次运行都重新编译代码&#xff0c;可以按照以下步…