[linux_C语言_udp的多种实现方法及网络调试中遇到的问题]

news2024/11/17 9:57:05

linux_C语言_udp的多种实现方法

  • 最基本的方式(不用组播不用sigio信号不使能广播属性)
    • 接收端
    • 发送端
  • 使用SIGIO信号的方式(使用sigio信号使用广播使能属性)
    • 服务端
    • 客户端
  • 使用组播模式
    • 服务端
    • 客户端
  • tcp和udp的使用区别
  • 调试中遇到的问题
  • 所有源码下载点这~~

最基本的方式(不用组播不用sigio信号不使能广播属性)

接收端

// 1,创建UDP套接字
int fd = Socket(AF_INET, SOCK_DGRAM, 0);

// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);

addr.sin_family = AF_INET;
inet_aton("192.168.45.153", &addr.sin_addr); // 绑定指定的IP,并做了字节序转换
//addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定自动获取的IP好像一般为0.0.0.0
addr.sin_port  = htons(50001);

// 3,绑定地址
Bind(fd, (struct sockaddr *)&addr, len);

// 5,静静地等待对方的信件...
char buf[100];
int flag=0;
while (1)
{
	// 4,准备接受对方的地址信息
	struct sockaddr_in peeraddr;
	len = sizeof(peeraddr);
	bzero(&peeraddr, len);
	bzero(buf, 100);
	if (recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len) != 0)//此函数用于UDP套接字接受数据
	{
		flag = 1;
	}

	printf("收到【%s:%hu】的信息: %s",
		inet_ntoa(peeraddr.sin_addr),
		ntohs(peeraddr.sin_port),
		buf);

	if (flag == 1)
	{
		sendto(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, len);//此函数用于向UDP套接字发送数据
		flag = 0;
	}
	printf("发送完毕\n");
}

发送端

char buf[100];
// 1,创建UDP套接字
int fd = Socket(AF_INET, SOCK_DGRAM, 0);

struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);

addr.sin_family = AF_INET;
inet_aton("192.168.45.153", &addr.sin_addr); // 绑定指定的IP,并做了字节序转换(字符串转二进制)
// addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定自动获取的IP
addr.sin_port = htons(50001);

while (1)
{
	bzero(buf, 100);
	scanf("%s", buf);
	getchar();
	sendto(fd, buf, 100, 0, (struct sockaddr *)&addr, len);
	printf("发送完毕\n");

	// 4,准备接受对方的地址信息
	struct sockaddr_in peeraddr;
	len = sizeof(peeraddr);
	bzero(&peeraddr, len);

	// 5,静静地等待对方的信件...
	buf[100];
	bzero(buf, 100);
	recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);

	printf("收到【%s:%hu】的信息: %s",
		inet_ntoa(peeraddr.sin_addr),//字节序转换(二进制转)
		ntohs(peeraddr.sin_port),
		buf);
}

使用SIGIO信号的方式(使用sigio信号使用广播使能属性)

服务端

注意事项:
因为客户端会使能广播属性向所有地址(255.255.255.255)进行数据发送
所以这里不能特定指定服务器为某网卡ip地址:inet_aton(“192.168.45.153”, &addr.sin_addr);
这会导致客户端那边发送服务器接受数据失败的情况

// 1,创建UDP套接字
fd = Socket(AF_INET, SOCK_DGRAM, 0);

// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);

addr.sin_family = AF_INET;
//inet_aton("x.x.x.x", &addr.sin_addr); // 绑定指定的IP,并做了字节序转换
addr.sin_addr.s_addr = htonl(INADDR_ANY); // 绑定一个本机的任意可用IP
// inet_aton("192.168.45.153", &addr.sin_addr);//这里需要注意使能广播属性后不能指定IP,不然客户端对255.255.255.255广播地址进行数据发送会接受不到统一用INADDR_ANY
addr.sin_port  = htons(50002);

// 3,绑定地址
Bind(fd, (struct sockaddr *)&addr, len);

// 4,用信号的方式来异步地接收各个客户端发来的UDP信息...

// a. 捕捉信号SIGIO
signal(SIGIO, f);

// b. 设置套接字为异步工作模式(即使之收到数据是产生信号SIGIO)
long flag = fcntl(fd, F_GETFL);
flag |= O_ASYNC;
fcntl(fd, F_SETFL, flag);

// c. 指定本进程为信号的属主
fcntl(fd, F_SETOWN, getpid());


// 服务器忙别的事情
int i=0;
while(1)
{
	i++;
	printf("%d\n",i);
	sleep(1);
}
// 准备接受对方的地址信息
struct sockaddr_in peeraddr;
socklen_t len = sizeof(peeraddr);
bzero(&peeraddr, len);

char buf[100];
bzero(buf, 100);
recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);	

printf("收到【%s:%hu】的信息: %s",
		inet_ntoa(peeraddr.sin_addr),
		ntohs(peeraddr.sin_port),
		buf);
// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
len = sizeof(addr);
bzero(&addr, len);

addr.sin_family = AF_INET;
inet_aton("255.255.255.255", &addr.sin_addr); // 准备好客户端的IP
addr.sin_port = htons(ntohs(peeraddr.sin_port)); // 准备好客户端的PORT
// 3,使能广播属性
int on = 1;
Setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

sendto(fd, buf, 100, 0, (struct sockaddr *)&addr, len);

客户端

// 1,创建UDP套接字
int fd = Socket(AF_INET, SOCK_DGRAM, 0);
int ret;
// 2,准备跟AF_INET(即IPv4网络层协议)对应的特定IP+PORT地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);

// 4,广播消息
char buf[100];

while(1)
{
	bzero(&addr, len);

	addr.sin_family = AF_INET;
	inet_aton("255.255.255.255", &addr.sin_addr); // 准备好服务器的IP
	// inet_aton("192.168.45.153", &addr.sin_addr);
	addr.sin_port = htons(50002); // 准备好服务器的PORT

	// 3,使能广播属性
	int on = 1;
	Setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

	bzero(buf, sizeof(buf));
	fgets(buf,100,stdin);
	ret = sendto(fd, buf, 100, 0, (struct sockaddr *)&addr, len);
	printf("RETURN %d\n",ret);
	// 准备接受对方的地址信息
	struct sockaddr_in peeraddr;
	socklen_t len = sizeof(peeraddr);
	bzero(&peeraddr, len);

	char buf[100];
	bzero(buf, 100);
	recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);

	printf("收到【%s:%hu】的信息: %s",
		inet_ntoa(peeraddr.sin_addr),
		ntohs(peeraddr.sin_port),
		buf);
}

使用组播模式

服务端

// 1,创建UDP套接字
int fd = socket(AF_INET, SOCK_DGRAM, 0);

// 2,准备地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port  = htons(atoi(argv[1]));

// 3,绑定地址
bind(fd, (struct sockaddr *)&addr, len);

// 4,使能广播属性
int on = 1;
setsockopt(fd, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on));

// 5,准备好组播地址结构体
struct sockaddr_in addr2;
socklen_t len2 = sizeof(addr2);
bzero(&addr2, len2);

addr2.sin_family = AF_INET;
addr2.sin_addr.s_addr = inet_addr("224.0.0.100");
addr2.sin_port  = htons(50003);

// 6,静静地等待客户端的数据
char buf[100];
while(1)
{
	struct sockaddr_in peeraddr;
	socklen_t len = sizeof(peeraddr);
	bzero(&peeraddr, len);
	bzero(buf, 100);
	recvfrom(fd, buf, 100, 0, (struct sockaddr *)&peeraddr, &len);

	printf("收到【%s:%hu】的信息: %s",
			inet_ntoa(peeraddr.sin_addr),
			ntohs(peeraddr.sin_port),
			buf);
	// 转发到组播中
	if(sendto(fd, buf, strlen(buf), 0,
			(struct sockaddr *)&addr2, len2) == -1)
	{
		perror("sendto failed");
	}
}

客户端

// 1,创建UDP套接字
fd = socket(AF_INET, SOCK_DGRAM, 0);


// 2,准备存放自身地址的结构体
struct sockaddr_in myaddr;
socklen_t mylen = sizeof(myaddr);
bzero(&myaddr, mylen);

myaddr.sin_family = AF_INET;
myaddr.sin_addr.s_addr = htonl(INADDR_ANY);
myaddr.sin_port  = htons(50003);

// 3,绑定固定的地址,方便服务器主动给我发数据
bind(fd, (struct sockaddr *)&myaddr, mylen);


// 4,加入指定的多播组
struct ip_mreq m;
bzero(&m, sizeof(m));

m.imr_multiaddr.s_addr =  inet_addr("224.0.0.100");
m.imr_interface.s_addr =  htonl(INADDR_ANY);

setsockopt(fd, IPPROTO_IP, IP_ADD_MEMBERSHIP, &m, sizeof(m));


// a. 捕捉信号SIGIO
signal(SIGIO, f);

// b. 设置套接字为异步工作模式(即使之收到数据是产生信号SIGIO)
long flag = fcntl(fd, F_GETFL);
flag |= O_ASYNC;
fcntl(fd, F_SETFL, flag);

// c. 指定本进程为信号的属主
fcntl(fd, F_SETOWN, getpid());


// 5,准备对端服务器的地址结构体
struct sockaddr_in addr;
socklen_t len = sizeof(addr);
bzero(&addr, len);

addr.sin_family = AF_INET;
addr.sin_addr.s_addr = inet_addr(argv[1]);
addr.sin_port  = htons(atoi(argv[2]));

// 6,不断给服务器发送数据
//    当收到服务器发来的组播消息时,会触发SIGIO
//    继而会使得 fgets() 出错返回
char buf[100];
while(1)
{
	bzero(buf, 100);
	if(fgets(buf, 100, stdin) == NULL)
	{
		perror("fgets failed");
		continue;
	}

	sendto(fd, buf, strlen(buf), 0,
			(struct sockaddr *)&addr, len);
}

tcp和udp的使用区别

tcp具有可靠性所以一般用于cmd命令的一些重要信息收发
udp则速度比较快,一般用于数据的发送比如音视频数据

调试中遇到的问题

  1. 客户端发送数据服务器能接受,服务器(运行在设备端)发送数据客户端(运行在ubuntu)无响应
    解决方法是:设备端添加对应网关即可对应解决。
    网关:网关就像一个搬运工,当没设网关时就等于没人帮你发送报文
    所以当tcp和udp服务器和客户端在不同网段开发时更要记得设置网关啦
  2. tcp开发客户端和服务器不同网段的时候connect不上问题,服务器:(ip:192.168.1.17、gw:192.168.1.1),客户端(ip:192.190.1.2、gw:192.190.1.1)
    最后发现是掩码问题导致,解决方法两边各设置一下:
    在这里插入图片描述
    在这里插入图片描述
    如果同网段下是这样设置的:(举个例子)
    ifconfig ens33 192.168.1.17 netmask 255.255.255.0
    route add -net 255.255.255.0 netmask 255.255.255.0 dev ens33

所有源码下载点这~~

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

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

相关文章

Unix/Linux编程:UDS 流(Stream)

〇、前言 socket 是一种 IPC (Inter-Process Communication,进程间通信)方法,它允许位于同一主机(计算机)或使用网络连接起来的不同主机上的应用程序之间交换数据。通过使用Socket,开发人员可以…

【C++】——栈和队列(stack、queue)及优先队列(priority_queue)的介绍和模拟实现

文章目录 1. 前言2. 容器适配器2.1 容器适配器的介绍2.2 STL标准库中stack和queue的底层结构2.3 deque的简单介绍2.4 deque的缺陷2.5 为什么选择deque作为stack和queue的底层默认容器 3. stack3.1 stack的介绍3.2 stack的使用3.3 stack模拟实现 4. queue4.1 queue的介绍4.2 que…

数据分布——长尾分布的处理

前言 长尾分布在分类任务中会提到这个名,这是因为长尾分布这个现象问题会导致在训练过程中会出现出错率高的问题,影响了实验结果。 这里要说的是,长尾分布是一种现象,有的地方说是一种理论或定律,我感觉这样说不太确切&#xff0…

取石子游戏——算法与编程

取石子游戏 目录 问题描述输入输出格式输入格式:输出格式: 输入输出样例输入样例#1:输出样例#1:提示信息 算法尼姆博奕 代码 问题描述 A l i c e Alice Alice和 B o b Bob Bob在玩取石子游戏,摆在他们面前的有 n n n堆…

GIS入门进阶之012

一、引言 空间数据可视化是有效传输与表达地理信息,挖掘空间数据之间的内在联系,揭示地理现象内在规律的重要手段。它通过运用地图学、计算机图形学和图像处理技术,将地学信息的输入、处理、查询、分析与预测的结果采用符号、图形、图像并结合…

OpenGL 材质实现

1.简介 在现实世界里,每个物体会对光产生不同的反应。比如,钢制物体看起来通常会比陶土花瓶更闪闪发光,一个木头箱子也不会与一个钢制箱子反射同样程度的光。有些物体反射光的时候不会有太多的散射,因而产生较小的高光点&#xf…

35岁被淘汰?软件测试工程师职业生涯规划,从技术到管理...

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 入门阶段&#xf…

Parallel Desktop中按照的centos在切换root用户时,密码正确,但一直切换不成功,显示su: Authentication failure

目录 一、出现问题二、分析问题三、解决问题四、参考资料 一、出现问题 我的密码明明是输入正确的,但又一直给我报下面的错误 二、分析问题 我怀疑是我密码记错了,所以我点击Log Out,重新去输入了一下密码,发现是正确的我确认…

[学习笔记] [机器学习] 9. 朴素贝叶斯(概率基础、联合概率、条件概率、贝叶斯公式、情感分析)

视频链接数据集下载地址:无需下载 学习目标: 4. 说明条件概率与联合概率 5. 说明贝叶斯公式、以及特征独立的关系 6. 记忆贝叶斯公式 7. 知道拉普拉斯平滑系数 8. 应用贝叶斯公式实现概率的计算 9. 会使用朴素贝叶斯对商品评论进行情感分析 1. 朴素贝叶…

对象进阶-继承、原型-原型链

工厂方法创建对象 我们之前已经学习了如何创建一个对象,那我们要是想要创建多个对象又该怎么办?聪明的同学可能会说,直接在写几个对象不就好了吗?比如下边的代码: var person1 {name: "孙悟空",age: 18,s…

APP自动化测试,Appium+PO模式+Pytest框架实战—项目案例

目录:导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结(尾部小惊喜) 前言 PO模式&#xff1…

如何解决GEE导出影像的Nodata值在ArcGIS中无法正常显示?

目录 01 ArcGIS对于GEE掩膜影像的Nodata值的说明 02 处理方法 2.1 方法1-GEE修改掩膜值 Arguments: Returns: Image 2.2 方法2-ArcGIS重新赋值Nodata(推荐) 01 ArcGIS对于GEE掩膜影像的Nodata值的说明 当在GEE中进行掩膜后,将影像在Ar…

打造极简风格动效 —— 5 分钟轻松实现惊艳、震撼人心的视觉效果

前期回顾 是不是在为 API 烦恼 ?好用免费的api接口大全呼之欲出_免流接口api_彩色之外的博客-CSDN博客APi、常用框架、UI、文档—— 整理合并https://blog.csdn.net/m0_57904695/article/details/130459417?spm1001.2014.3001.5501 👍 本文专栏&…

20道嵌入式经典面试题(附答案)

1.嵌入式系统中经常要用到无限循环,如何用C编写死循环 答:while(1){} 或者 for(;;) 2.程序的局部变量存在于哪里,全局变量存在于哪里,动态申请数据存在于哪里。 答:程序的局部变量存在于栈区;全局变量存在…

【Linux】浅谈文件原理与操作

目录 问题引入 浅谈文件原理 文件操作 文件的打开与关闭 open close write与read 再谈C库文件操作 问题引入 🌸以前我们学过C语言的文件操作,而不同语言的文件操作都是不一样的,我们该如何理解这一现象,能不能用一种统一…

有关 string 类的练习(下)

目录 一、反转字符串 II 二、反转字符串中的单词 III 三、找出字符串中第一个只出现一次的字符 四、字符串相乘 五、把字符串转换成整数 一、反转字符串 II 给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转…

Spring,注解开发

Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架 1、组成 spring七大模块详解 2、IOC理论推导 传统的开发 (pojo层、DAO层和业务层) (1)UserDao (2) UserDaoImpl (3)…

天狼星-大熊座 Ursa Major SIRIUS

大熊座 Ursa Major SIRIUS 键盘说明 客制化键盘: 大熊座 Ursa Major SIRIUS 配列: 75 键帽:KCA-HelloWorld-Black 双模: 蓝牙-分裂方案 驱动配置:Link Lab 驱动设置软件 键盘操作 键盘说明参考:键位配…

利用WinDbg查看堆栈中方法入参的值4(C#)

由于作者水平有限,如有写得不对的地方,请指正。 使用WinDbg的过程中,坑特别的多,对版本要求比较严格,如: 1 32位应用程序导出的Dump文件要用32位的WinDbg打开,想要没有那么多的问题&#xf…

海底光缆位置探测技术的应用概述

1. 概述 海底光缆运行在地质环境复杂的海洋环境中,地震、海床塌陷、滑坡、洋流变化、海洋生物及船只抛锚都有可能造成光缆断裂、破损,影响光缆的安全运行。海底光缆一旦遭受损坏,其造成的经济损失无法估量。因此在海洋开发工程实施前&#xf…