华清远见嵌入式学习——网络编程——小项目

news2024/11/18 0:45:50

项目要求:

代码实现:

服务器端:

#include <myhead.h>

//定义协议包
struct proto
{
	char type;
	char name[20];
	char text[128];	
};


int main(int argc, const char *argv[])
{
	//判断从终端输入的字符串的个数
	if(argc != 3)
	{
		printf("input error\n");
		printf("usage:./a.out 本机IP 本机端口\n");
		return -1;
	}

	//创建用于通信的套接字
	int sfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sfd == -1)
	{
		perror("socket error");
		return -1;
	}

	//设置端口号快速重用
	int reuse = 1;
	if(setsockopt(sfd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1)
	{
		perror("setsockopt error");
		return -1;
	}

	//绑定服务器IP和端口号
	填充服务器地址信息结构体
	short port = (short)atoi(argv[2]);
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	sin.sin_port = htons(port);

	绑定
	if(bind(sfd,(struct sockaddr *)&sin,sizeof(sin)) == -1)
	{
		perror("bind error");
		return -1;
	}

	//定义客户端地址信息结构体
	struct sockaddr_in cin;
	cin.sin_family = AF_INET;

	socklen_t socklen = sizeof(cin);

	//定义客户端地址信息结构体数组,用于存放多个客户端地址信息
	struct sockaddr_in savecin[1024];

	//初始化每个信息结构体内的第一个成员
	for(int i = 0;i < 1024;i++)
	{
		savecin[i].sin_family = AF_INET;
	}

	定义一个用于检测文件描述符的集合
	fd_set readfds, tempfds;                          //在栈区定义

	清空容器中的内容
	FD_ZERO(&readfds);
	将要检测的文件描述符放入集合中
	FD_SET(sfd, &readfds);           //将sfd文件描述符放入
	FD_SET(0, &readfds);             //将0号文件描述符放入

	//对客户端的数据进行保存和转发

	char buf[256] = "";
	int res1,res2;
	int n = 0;

	//定义协议包结构体变量
	struct proto pro;
	struct proto send;

	while(1)
	{
		bzero(buf,sizeof(buf));

		tempfds = readfds;

		使用select阻塞等待集合中的文件描述符有事件产生
		res1 = select(sfd+1, &tempfds, NULL, NULL, NULL);
		if(res1 == -1)
		{
			perror("select error");
			return -1;
		}else if(res1 == 0)
		{
			printf("time out\n");
			return -1;
		}


		//接收客户端信息
		if(FD_ISSET(sfd,&tempfds))
		{
			res2 = recvfrom(sfd,&pro,sizeof(pro),0,(struct sockaddr *)&cin,&socklen);
			if(res2 == -1)
			{
				perror("recvfrom error");
				return -1;
			}

			//登录时存储客户端到数组中
			if(pro.type == 'L')
			{
				savecin[n] = cin;
				n++;

				sprintf(buf,"---%s已上线---",pro.name);

				printf("%s\n",buf);
				for(int i = 0;i < n;i++)
				{
					if(savecin[i].sin_port == cin.sin_port)
					{
						continue;
					}	
					sendto(sfd,&pro,sizeof(pro),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));

				}


			}


			if(pro.type == 'C')
			{
					//群聊
					send.type = pro.type;
					strcpy(send.name,pro.name);
					strcpy(send.text,pro.text);

					for(int i = 0;i < n;i++)
					{
						if(savecin[i].sin_port == cin.sin_port)
						{
							continue;
						}	
						sendto(sfd,&send,sizeof(send),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));

					}

			}
			if(pro.type == 'Q')
			{
				//下线
				send.type = pro.type;
				strcpy(send.name,pro.name);
				strcpy(send.text,pro.text);

				for(int i = 0;i < n;i++)
				{
					bzero(buf,sizeof(buf));

					sprintf(buf,"---%s已下线---\n",send.name);

					printf("%s\n",buf);



					//删除该用户
					if(savecin[i].sin_port == cin.sin_port)
					{
						int t = i;
						for(int j = i;j <= n;j++)
						{
							savecin[t] = savecin[t+1];
							t++;				
						}
					}
					n--;
					sendto(sfd,&send,sizeof(send),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));

				}
			}
		}
		if(FD_ISSET(0,&tempfds))
		{
			bzero(send.name,sizeof(send.name));
			bzero(send.text,sizeof(send.text));

			send.type = 'C';
			strcpy(send.name,"系统消息");

			fgets(send.text,sizeof(send.text),stdin);
			send.text[strlen(send.text)-1] = '\0';

			for(int i = 0;i <= n;i++)
			{


				sendto(sfd,&send,sizeof(send),0,(struct sockaddr *)&savecin[i],sizeof(savecin[i]));
			}	
		}
	}
	//关闭套接字文件描述符
	close(sfd);
	return 0;
}

客户端:

#include <myhead.h>

//定义协议包结构体
struct proto
{
	char type;
	char name[20];
	char text[128];
};

int main(int argc, const char *argv[])
{
	//判断终端输入的字符串的个数
	if(argc != 3)
	{
		printf("input error\n");
		printf("usage:./a.out 服务器IP 服务器端口号\n");
		return -1;
	}

	//创建用于通信的套接字
	int cfd = socket(AF_INET,SOCK_DGRAM,0);
	if(cfd == -1)
	{
		perror("socket error");
		return -1;
	}

	//填充服务器地址信息结构体
	short port = (short)atoi(argv[2]);	
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	sin.sin_port = htons(port);
	socklen_t socklen = sizeof(sin);

	//定义协议包结构体变量
	struct proto pro;


	//填充登录协议

	printf("请输入姓名>>");

	//登录
	pro.type = 'L'; 

	fgets(pro.name,sizeof(pro.name),stdin);
	pro.name[strlen(pro.name)-1] = '\0';

	sendto(cfd,&pro,sizeof(pro),0,(struct sockaddr *)&sin,sizeof(sin));

	定义一个用于检测文件描述符的集合
	fd_set readfds, tempfds;                          //在栈区定义

	清空容器中的内容
	FD_ZERO(&readfds);
	将要检测的文件描述符放入集合中
	FD_SET(cfd, &readfds);           //将sfd文件描述符放入
	FD_SET(0, &readfds);             //将0号文件描述符放入

	//向服务器发送或从服务器接收消息
	char rbuf[128] = "";
	int res = 0;
	char name1[20] = "";
	strcpy(name1,pro.name);


	while(1)
	{

		将集合内容复制一份
		tempfds = readfds;

		使用select阻塞等待集合中的文件描述符有事件产生
		res = select(cfd+1, &tempfds, NULL, NULL, NULL);
		if(res == -1)
		{
			perror("select error");
			return -1;
		}else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}

		//群聊和退出
		if(FD_ISSET(0,&tempfds))
		{
			bzero(pro.text,sizeof(pro.text));
			
			//从终端获取内容
			fgets(pro.text,sizeof(pro.text),stdin);
			pro.text[strlen(pro.text)-1] = '\0';

			if(strcmp(pro.text,"quit") == 0)
			{
				//退出
				pro.type = 'Q';
				sendto(cfd,&pro,sizeof(pro),0,(struct sockaddr *)&sin,sizeof(sin));

				//关闭套接字文件描述符
				close(cfd);


				break;
			}else
			{
				//群聊
				pro.type = 'C';
				sendto(cfd,&pro,sizeof(pro),0,(struct sockaddr *)&sin,sizeof(sin));

			}
		}

		//接收来自服务器的消息
		if(FD_ISSET(cfd,&tempfds))
		{

			bzero(rbuf,sizeof(rbuf));
			bzero(pro.text,sizeof(pro.text));

			res = recvfrom(cfd,&pro,sizeof(pro),0,NULL,NULL);
			if(res < 0)
			{
				perror("recvfrom error");
				return -1;
			}

			if(pro.type == 'L')
			{
				printf("---%s已登录---\n",pro.name);
			}
			if(pro.type == 'C')
			{
				printf("%s:%s\n",pro.name,pro.text);
				if(strcmp(pro.name,"系统消息") == 0)
				{
					strcpy(pro.name,name1);
				}
			}
			if(pro.type == 'Q')
			{
				printf("---%s已下线---\n",pro.name);
			}
		}


	}
	//关闭套接字文件描述符
	close(cfd);

	return 0;
}

代码运行效果图:

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

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

相关文章

【算法萌新闯力扣】:卡牌分组

力扣热题&#xff1a;卡牌分组 一、开篇 今天是备战蓝桥杯的第22天。这道题触及到我好几个知识盲区&#xff0c;以前欠下的债这道题一并补齐&#xff0c;哈希表的遍历、最大公约数与最小公倍数&#xff0c;如果你还没掌握&#xff0c;这道题练起来&#xff01; 二、题目链接:…

别再被面试官问倒了!快速失败与安全失败的区别详解

大家好&#xff0c;我是小米&#xff0c;一个热爱技术分享的程序员大哥哥。今天&#xff0c;我们来聊一个在Java面试中经常会被问到的问题——"快速失败"&#xff08;fail-fast&#xff09;和"安全失败"&#xff08;fail-safe&#xff09;的区别。这两个概…

45岁后,3部位“越干净”,往往身体越健康,占一个也要恭喜!

众所周知&#xff0c;人的生命有长有短&#xff0c;而我们的身体健康状态&#xff0c;也同样会受到年龄的影响&#xff0c;就身体的年龄层次而言&#xff0c;往往需要我们用身体内部的干净程度来维持&#xff0c;换句话说就是&#xff1a;若是你的身体内部越干净&#xff0c;那…

【接口技术】实验2:基本I/O实验

实验2 基本I/O实验 一、实验目的 1&#xff1a;掌握I/O端口地址译码电路的工作原理。 2&#xff1a;掌握简单并行接口的工作原理及使用方法。 二、实验内容 1&#xff1a;I/O端口地址译码实验 I/O地址译码电路不仅与地址信号有关&#xff0c;而且与控制信号有关。参加译码…

【面试HOT200】滑动窗口篇

系列综述&#xff1a; &#x1f49e;目的&#xff1a;本系列是个人整理为了秋招面试的&#xff0c;整理期间苛求每个知识点&#xff0c;平衡理解简易度与深入程度。 &#x1f970;来源&#xff1a;材料主要源于【CodeTopHot200】进行的&#xff0c;每个知识点的修正和深入主要参…

Flink实战(11)-Exactly-Once语义之两阶段提交

0 大纲 [Apache Flink]2017年12月发布的1.4.0版本开始&#xff0c;为流计算引入里程碑特性&#xff1a;TwoPhaseCommitSinkFunction。它提取了两阶段提交协议的通用逻辑&#xff0c;使得通过Flink来构建端到端的Exactly-Once程序成为可能。同时支持&#xff1a; 数据源&#…

【问题思考总结】多维随机变量函数的分布的两种情况的计算方法【离连/连连】

问题 今天做李六第一套的时候发现&#xff0c;有的时候&#xff0c;面对这种第二问的题&#xff0c;很自然地就想到了Fz&#xff08;z&#xff09;&#xff0c;然后进行化简&#xff0c;但是有的时候&#xff0c;像这道题&#xff0c;就突然发现P{XY<z}是一个非常复杂的形式…

The Bridge:从临床数据到临床应用(预测模型总结)

The Bridge:从临床数据到临床应用&#xff08;预测模型总结&#xff09; 如果说把临床预测模型比作临床数据和临床应用之间的一座“桥梁”&#xff0c;那它应该包括这样几个环节&#xff1a;模型的构建和评价、模型的概率矫正、模型决策阈值的确定和模型的局部再评价。 模型的构…

Qt 串口编程-从入门到实战

1. Qt 串口通信流程解析 1.1 串行通信和并行通信对比 并行通信适合距离较短的通信&#xff0c;且信号容易受干扰&#xff0c;成本高串口通讯-设备&#xff08;蓝牙&#xff0c; wifi&#xff0c; gprs&#xff0c; gps&#xff09; 1.2 Qt 串口通信具体流程 1. 创建 QSerial…

渗透测试--Nacos系统

免责声明&#xff1a; 文章中涉及的漏洞均已修复&#xff0c;敏感信息均已做打码处理&#xff0c;文章仅做经验分享用途&#xff0c;切勿当真&#xff0c;未授权的攻击属于非法行为&#xff01;文章中敏感信息均已做多层打马处理。传播、利用本文章所提供的信息而造成的任何直…

从零到Kafka:万字带你体验Spring Boot整合消息驱动的奇妙之旅

Spring Boot与Kafka从零开始整合指南 准备工作创建项目 Spring Boot与Kafka的初次邂逅配置生产者消费者模拟测试 消息处理生产者发送消息消费者处理消息自定义序列化器 主页传送门&#xff1a;&#x1f4c0; 传送 准备工作 Spring boot: &#xff5c; 基于Spring的开源框架&a…

scipy 笔记:scipy.spatial.distance

1 pdist 计算n维空间中观测点之间的成对距离。 scipy.spatial.distance.pdist(X, metriceuclidean, *, outNone, **kwargs) 1.1 主要参数 X一个m行n列的数组&#xff0c;表示n维空间中的m个原始观测点metric使用的距离度量out输出数组。如果非空&#xff0c;压缩的距离矩阵…

每日一题:LeetCode-103/107.二叉树的(层序/锯齿形层序)遍历

每日一题系列&#xff08;day 04&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

interface previously declared 的bug问题

其实就是重复定义了&#xff0c;只需要加如下的代码即可&#xff1a; 其中把APB的部分改成自己的接口名字就好了。

『亚马逊云科技产品测评』活动征文|EC2 实例安装 docker 与配套软件部署前后端分离的医疗管理后台系统

授权声明&#xff1a;本篇文章授权活动官方亚马逊云科技文章转发、改写权&#xff0c;包括不限于在 Developer Centre, 知乎&#xff0c;自媒体平台&#xff0c;第三方开发者媒体等亚马逊云科技官方渠道 目录 一、AWS 产品类别选择 &#xff08;1&#xff09;应用服务器选择…

【接口技术】实验1:简易汇编程序调试

实验1 简易汇编程序调试 一、实验目的 1&#xff1a;掌握在集成开发软件环境中汇编程序的编写、调试方法。 2&#xff1a;学会用DOS功能调用&#xff08;1号和2号&#xff09;完成输入和输出。 二、实验内容 1-1&#xff1a; 在以BUF为首地址的字节存储区存放有若干个无符…

02 RANSAC算法 及 Python 实现

文章目录 02 RANSAC算法 及 Python 实现2.1 简介2.2 算法流程2.3 RANSAC 算法实现直线拟合2.4 利用 RANSAC 算法减少 ORB 特征点误匹配 02 RANSAC算法 及 Python 实现 2.1 简介 RANSAC &#xff08;Random Sample Consensus&#xff0c;随机抽样一致&#xff09;算法的 基本假…

网络通信基础概念介绍

网络通信基础概念介绍 局域网LAN 局域网&#xff0c;即 Local Area Network&#xff0c;简称LAN。 局域网内的主机之间能方便的进行网络通信&#xff0c;又称为内网&#xff1b;局域网和局域网之间在没有连接的情况下&#xff0c;是无法通信的。 局域网是指在一个相对较小的…

Android设计模式--外观模式

弈之为术&#xff0c;在人自悟 一&#xff0c;定义 外观模式要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。提供一个高层次的接口&#xff0c;使得子系统更易于使用。 外观模式在开发中的使用频率是非常高的&#xff0c;尤其是在第三方的SDK里面&#xff0…

redis运维(二十)redis 的扩展应用 lua(二)

一 redis 的扩展应用 lua redis lua脚本语法 ① 什么是脚本缓存 redis 缓存lua脚本 说明&#xff1a; 重启redis,脚本缓存会丢失 下面讲解 SCRIPT ... 系列 SCRIPT ② LOAD 语法&#xff1a;SCRIPT LOAD lua代码 -->载入一个脚本,只是预加载,不执行思考1&#xff1…