基于UDP实现的网络聊天室

news2025/1/15 19:33:13

服务器:

#include <myhead.h>
struct msg
{
	char type;
	char name[20];
	char text[1024];
};

int main(int argc, const char *argv[])
{
	if(argc!=3)
	{
		printf("input error\n");
		printf("./a.out IP地址 端口号\n");
		return -1;
	}

    //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;                                                                     
        }  

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


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

	 //定义容器接收对端地址信息结构体
    struct sockaddr_in cin;
    socklen_t socklen = sizeof(cin);

	//定义存储客户端地址信息结构体信息
	struct sockaddr_in scin[1024];
	for(int i=0;i<1024;i++)
	{
		scin[i].sin_family=AF_INET;
	}

	 //1、创建文件描述符容器
    fd_set readfds, tempfds;
    //2、清空容器内容
    FD_ZERO(&readfds);
    //3、将sfd和0号文件描述符放入容器中
    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);

	//定义结构体变量,用于接收和发送,和客户端进行通信
	struct msg send;
	struct msg in;
	
	int res;
	char buf[128]="";
	char address[128]="";
	int n=0;

	while(1)
	{
		bzero(buf,sizeof(buf));
		bzero(address,sizeof(address));
		tempfds = readfds;      //将要检测的容器复制保存一份
	    res = select(sfd+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(sfd,&tempfds))
		{
			res=recvfrom(sfd,&in,sizeof(in),0,(struct sockaddr*)&cin,&socklen);
			if(res==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			if(in.type=='L')
			{
				scin[n]=cin;
				n++;
			//	sprintf(buf,"---%s 已上线---",in.name);
				sprintf(address,"---%s[%s:%d]登录成功---",in.name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
				printf("%s\n",address);
				for(int i=0;i<n;i++)
				{
					if(scin[i].sin_port==cin.sin_port)
					{
						continue;
					}
					sendto(sfd,&in,sizeof(in),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));
				}
				bzero(address,sizeof(address));
			}
			if(in.type=='C')
			{
				sprintf(address,"---%s[%s:%d]chat成功---",in.name,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));
				printf("%s\n",address);

				//群聊
				send.type=in.type;
				strcpy(send.name,in.name);
				strcpy(send.text,in.text);
				for(int i=0;i<n;i++)
				{
					if(scin[i].sin_port==cin.sin_port)
					{
						continue;
					}
					sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));


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

				for(int i=0;i<n;i++)
				{
					bzero(buf,sizeof(buf));
					sprintf(buf,"---%s已下线---\n",send.name);
					printf("%s\n",buf);
					//删除用户
					if(scin[i].sin_port==cin.sin_port)
					{
						int t=i;
						for(int j=i;j<=n;j++)
						{
							scin[t]=scin[t+1];
							t++;
						}
					}
					n--;
					sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));
				}
			
			}
		}
		if(FD_ISSET(0,&tempfds))
		{
			//用于接收系统的消息
			bzero(&send,sizeof(send));
			strcpy(send.name,"系统消息");
			fgets(send.text,sizeof(send.text),stdin);
			send.text[strlen(send.text)-1]=0;
			send.type='C';
			for(int i=0;i<=n;i++)
			{
				sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&scin[i],sizeof(scin[i]));
			}
		}


	}

	close(sfd);



	return 0;
}

客户端:

#include <myhead.h>
struct msg
{
	char type;
	char name[20];
	char text[1024];
};

int main(int argc, const char *argv[])
{
	if(argc!=3)
	{
		printf("input error\n");
		printf("usage:./a.out IP地址 端口号\n");
		return -1;
	}

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

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



	//定义结构体变量,用于发送和接收
	struct msg send;
	struct msg in;
	printf("请输入用户名>>>");
	fgets(send.name,sizeof(send.name),stdin);
	send.name[strlen(send.name)-1]=0;
	send.type='L';
	//将登录的用户名发送给服务器
	sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&sin,socklen);
	
    //1、创建文件描述符容器
    fd_set readfds, tempfds;
    //2、清空容器内容
    FD_ZERO(&readfds);
    //3、将sfd和0号文件描述符放入容器中
    FD_SET(0, &readfds);
    FD_SET(sfd, &readfds);

	int res1;
	char buf[128]="";

	while(1)
	{
		 tempfds = readfds;      //将要检测的容器复制保存一份
        int res = select(sfd+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(sfd,&tempfds))
		{
			res1=recvfrom(sfd,&in,sizeof(in),0,(struct sockaddr*)&sin,&socklen);
			if(res1==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			if(in.type=='L')
			{
				printf("---%s上线了---\n",in.name);
			}
			if(in.type=='C')
			{
				printf("%s: %s\n",in.name,in.text);
			}
			if(in.type=='Q')
			{
				printf("---%s已下线---\n",in.name);
			}

		}
		//如果程序执行到此,说明检测的集合中有事件产生
        if(FD_ISSET(0, &tempfds))       //表示sfd触发了事件
		{
			//判断是群聊还是退出
			bzero(send.text,sizeof(send.text));
			fgets(send.text,sizeof(send.text),stdin);
			send.text[strlen(send.text)-1]=0;
			if(strcmp(send.text,"quit")==0)
			{
				send.type='Q';
				sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&sin,socklen);
				break;
			}else
			{
				send.type='C';
				sendto(sfd,&send,sizeof(send),0,(struct sockaddr*)&sin,socklen);
			}
		}

	}
	close(sfd);
	return 0;
}

运行结果:

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

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

相关文章

企业级Avatar道具解决方案

美摄科技&#xff0c;作为业界领先的多媒体解决方案提供商&#xff0c;近日推出了一款革命性的Avatar道具解决方案&#xff0c;旨在帮助企业打造独特且高度个性化的数字形象&#xff0c;从而提升企业品牌的吸引力和影响力。 这款解决方案的核心在于其先进的单摄像头Avatar生成…

MYSQL使用mysqldump备份、复原数据库

参考 添加链接描述 1. 备份数据库 C:\Windows\system32>mysqldump -uroot -p test student>C:\student.sql Enter password: ****2. 备份多个数据库 mysqldump -u root -p --databases test mysql>C:\testandmysql.sql3. 备份所有数据库 mysqldump -u root -p -…

R实现热图与网络图组合并显示显著性

大家好&#xff0c;我是带我去滑雪&#xff01; 热图和网络图分别展示了数据的不同方面。热图可用于显示变量之间的相关性或模式&#xff0c;而网络图则可用于显示节点之间的连接关系。通过将它们组合在一起&#xff0c;可以更全面地展示数据之间的关系和结构。下面开始代码实战…

数据结构界的终极幻神----树

目录 一.数的概念和分类 种类 二.重点概念 哈希树: 二叉树的线索化 什么是线索化 为什么要线索化 特殊的查找树 完全二叉树 三.手撕完全二叉树(堆) 重点讲解 向上搜索算法 向下搜索算法 一.数的概念和分类 树&#xff08;tree&#xff09;是包含 n(n≥0) [2] 个节…

机器学习笔记 DeepFakes和换脸技术简述

一、简述 人脸检测一直是 2000 年代初的主要研究课题。差不多二十年后,这个问题基本上得到了解决,并且人脸检测在大多数编程语言中都可以作为库使用。甚至换脸技术也不是什么新鲜事,并且已经存在了好些年了。 早在2016年左右就有基于OpenCV进行面部交换的方式了,主要是基于…

安卓玩机工具推荐----高通芯片9008端口读写分区 备份分区 恢复分区 制作线刷包 工具操作解析

上期解析了下adb端口备份分区的有关操作 安卓玩机工具推荐----ADB状态读写分区 备份分区 恢复分区 查看分区号 工具操作解析 在以往的博文中对于高通芯片机型的分区读写已经分享了很多。相关类似博文 安卓备份分区----手动查询安卓系统分区信息 导出系统分区的一些基本操作 …

【C++】C/C++内存管理详解

个人主页 &#xff1a; zxctscl 文章封面来自&#xff1a;艺术家–贤海林 如有转载请先通知 目录 1. 前言2. C/C内存分布3. C语言中动态内存管理方式4. C中动态内存管理4.1 new/delete操作内置类型4.2 new和delete操作自定义类型 5. operator new与operator delete函数5.1 oper…

【MySQL】not in遇上null的坑

今天遇到一个问题&#xff1a; 1、当 in 内的字段包含 null 的时候&#xff0c;正常过滤&#xff1b; 2、当 not in 内的字段包含 null 的时候&#xff0c;不能正常过滤&#xff0c;即使满足条件&#xff0c;最终结果也为 空。 测试如下&#xff1a; select * from emp e;当…

SoundTouch对音频处理(Android)

SoundTouch对音频处理&#xff08;Android&#xff09; SoundTouch介绍 SoundTouch 是一个用于音频处理的开源库&#xff0c;主要用于改变音频的速度、音调和音量等特征。您可以在项目中使用 SoundTouch 库来实现音频处理的功能&#xff0c;比如变速播放、音高变化、混响效果…

设计模式之模版方法实践

模版方法实践案例 实践之前还是先了解一下模版方法的定义 定义 模板方法模式是一种行为设计模式&#xff0c;它定义了一个骨架&#xff0c;并允许子类在不改变结构的情况下重写的特定步骤。模板方法模式通过在父类中定义一个模板方法&#xff0c;其中包含了主要步骤&#xf…

绳牵引并联机器人动态避障方法

绳牵引并联机器人在受限空间中如何躲避动态障碍物&#xff0c;是个有挑战的课题。 来自哈尔滨工业大学&#xff08;深圳&#xff09;的熊昊老师团队&#xff0c;开展了一项有趣的研究&#xff0c;论文《Dynamic Obstacle Avoidance for Cable-Driven Parallel Robots With Mob…

MySQL实战45讲——30答疑文章(二):用动态的观点看加锁

目录 不等号条件里的等值查询 等值查询的过程 怎么看死锁&#xff1f; 怎么看锁等待&#xff1f; update 的例子 小结 上期问题时间 提示 文章摘自林晓斌老师《MySQL实战45讲》&#xff0c;作为笔记而用&#xff0c;故有加一些自己的理解。在第[20]和[21]篇文章中&…

【Python】3. 基础语法(2) -- 语句篇

顺序语句 默认情况下, Python 的代码执行顺序是按照从上到下的顺序, 依次执行的. print("1") print("2") print("3")执行结果一定为 “123”, 而不会出现 “321” 或者 “132” 等. 这种按照顺序执行的代码, 我们称为 顺序语句. 这个顺序是很关…

2-web端管理界面使用rabbitmq

Web管理界面可以直接操作RabbitMQ&#xff0c;下面进行操作并记录步骤 1、添加交换器&#xff1a; Add a new exchange 中&#xff0c;Name是交换器名称&#xff0c;Type是交换器类型&#xff0c;有direce、fanout、heders、topic 4种。 这里先只填Name和选个类型&#xff0c;…

BurpSuite2024.2.1

1.更新介绍 此版本引入了特定的API 扫描功能&#xff0c;并将 Bambdas 合并到 Logger 捕获过滤器中。我们还改进了 DOM Invader 和 Burp Suite 导航记录器的功能&#xff0c;并进行了许多其他改进和错误修复。 API扫描 我们引入了特定的 API 扫描功能。您现在可以上传 OpenAP…

C语言数据结构(6)——队列

欢迎来到博主的专栏——C语言进阶指南 博主ID&#xff1a;代码小豪 文章目录 队列顺序结构的队列顺序队列的初始化顺序队列的入队列操作判断队列是否为空顺序队列的出队列操作顺序队列操作的所有代码 链式结构的队列链式队列的初始化链式队列的初始化链式队列的入队列操作链式…

Python读取.csv/.txt文件并画图

文章目录 读取.txt文件并画出每列数据读取.csv文件并画出每列数据python绘图的基本知识补充 读取.txt文件并画出每列数据 main.ipynb //注意文件类型为.ipynbimport matplotlib.pyplot as plt import numpy as npdata np.loadtxt(result.txt) fig plt.figure(dpi100,figsize…

TabLayout预览不了?

<TableLayoutandroid:layout_width"wrap_content"android:layout_height"wrap_content"/> 当然预览不了了&#xff0c;这其实不是我要的控件。 而实际需要的是TabLayout 不是TableLayout &#xff01;&#xff01;&#xff01; <com.google.an…

浅析extern关键字

C中extern关键字的使用 文章目录 C中extern关键字的使用前言正文1. C与C编译区别2. C调用C函数3. C中调用C函数 总结 前言 ​ C 是一种支持多范式的编程语言&#xff0c;它既可以实现面向对象的编程&#xff0c;也可以实现泛型编程和函数式编程。C 还具有与C语言的兼容性&…

2024.3.4 JAVA 复习

Java环境搭建 1、JDK和JRE的概述 JDK&#xff1a;Java开发工具包(Java Development Kit), 包含开发工具 和 JRE. 常用的开发工具: javac, java JRE&#xff1a;Java运行时环境(Java Runtime Environment), 包含运行Java程序时所需的核心类库和 JVM. 核心类库: java.lang, jav…