3.23项目:聊天室

1、 基于UDP的网络聊天室

项目需求:

  1. 如果有用户登录,其他用户可以收到这个人的登录信息
  2. 如果有人发送信息,其他用户可以收到这个人的群聊信息
  3. 如果有人下线,其他用户可以收到这个人的下线信息
  4. 服务器可以发送系统信息

服务器

#include <myhead.h>

//链表结构体
typedef struct Node
{
	char name[20];
	struct sockaddr_in cin;
	struct Node *next;   //指针域
}node,*node_p;

//数据结构体
struct msgTyp
{
	char type;
	char usrName[20];
	char msgText[1024];
};

//创建链表头结点
node_p create_head()
{
	node_p L = (node_p)malloc(sizeof(node));
	if(L == NULL)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	L->next = NULL;
	return L;
}

//创建结点
node_p create_node(char *name,struct sockaddr_in cin)
{
	node_p new = (node_p)malloc(sizeof(node));
	if(new == NULL)
	{
		printf("空间申请失败\n");
		return NULL;
	}
	strcpy(new->name,name);
	new->cin = cin;
	return new;
}

//头插
void insert(node_p L,char *name,struct sockaddr_in cin)
{
	if(L == NULL)
	{
		printf("入参为空\n");
		return;
	}
	node_p new = create_node(name,cin);
	new->next = L->next;
	L->next = new;
}

//按姓名删除
void delete(node_p L,char *name)
{
	if(L == NULL)
	{
		printf("入参为空\n");
		return;
	}
	node_p p = L;
	while(p != NULL)
	{
		if(strcmp(p->next->name,name) == 0)
		{
			node_p del = p->next;
			free(del);
			p->next = p->next->next;
			break;
		}
		p = p->next;
	}
}


int main(int argc, const char *argv[])
{
	//定义结构体变量
	node link;
	struct msgTyp msg;

	//创建链表
	node_p L = create_head();

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

	//判断是否有外部传参
	if(argc < 3)
	{
		printf("请输入IP和端口号\n");
		return -1;
	}

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

	//填写地址信息结构体
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(atoi(argv[2]));
	sin.sin_addr.s_addr = inet_addr(argv[1]);

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

	struct sockaddr_in cin;
	socklen_t addrlen = sizeof(cin);

	//定义一个文件描述符集合
	fd_set readfds,tempfds;

	//将集合清空
	FD_ZERO(&readfds);

	//将检测的文件描述符放入集合
	FD_SET(0,&readfds);
	FD_SET(sfd,&readfds);

	int maxfd = sfd;

	while(1)
	{
		//将readfds备份
		tempfds = readfds;

		int res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(res == -1)
		{
			perror("select error");
			return -1;
		}
		else if(res == 0)
		{
			printf("time out\n");
			return -1;
		}

		link.cin = cin;

		//数据的互通
		if(FD_ISSET(sfd,&tempfds))
		{
			recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&link.cin,&addrlen);
			//登录
			if(msg.type == 'L')
			{
				strcpy(link.name,msg.usrName);
				insert(L,link.name,link.cin);
				char arr[128] = "";
				sprintf(arr,"***%s登录成功***",msg.usrName);
				node_p p1 = L->next;
				while(p1 != NULL)
				{
					sendto(sfd,arr,sizeof(arr),0,(struct sockaddr*)&(p1->cin),sizeof(p1->cin));
					p1 = p1->next;
				}
				printf("%s [%s %d]:登录成功\n",link.name,inet_ntoa(link.cin.sin_addr),ntohs(link.cin.sin_port));
			}
			//聊天
			else if(msg.type == 'C')
			{
				strcpy(link.name,msg.usrName);
				char brr[2048] = "";
				sprintf(brr,"%s:%s",msg.usrName,msg.msgText);
				node_p p2 = L->next;
				//循环遍历
				while(p2 != NULL)
				{
					if(strcmp(p2->name,msg.usrName) != 0)
					{
						sendto(sfd,brr,sizeof(brr),0,(struct sockaddr*)&(p2->cin),sizeof(p2->cin));
					}
					p2 = p2->next;
				}
				printf("%s [%s %d]:chat成功\n",link.name,inet_ntoa(link.cin.sin_addr),ntohs(link.cin.sin_port));
			}
			//退出
			else if(msg.type == 'Q')
			{
				strcpy(link.name,msg.usrName);
				delete(L,link.name);
				char crr[128] = "";
				sprintf(crr,"***%s退出聊天***",msg.usrName);
				node_p p3 = L->next;
				while(p3 != NULL)
				{
					sendto(sfd,crr,sizeof(crr),0,(struct sockaddr*)&(p3->cin),sizeof(p3->cin));
					p3 = p3->next;
				}
				printf("%s [%s %d]:退出聊天\n",link.name,inet_ntoa(link.cin.sin_addr),ntohs(link.cin.sin_port));
			}
		}

		//系统发送信息
		if(FD_ISSET(0,&tempfds))
		{
			char sbuf[1024] = "";
			char buf[512] = "";
			fgets(buf,sizeof(buf),stdin);
			buf[strlen(buf)-1] = '\0';
			sprintf(sbuf,"**system**:%s",buf);
			node_p p = L->next;
			while(p != NULL)
			{
				if(sendto(sfd,sbuf,sizeof(sbuf),0,(struct sockaddr*)&(p->cin),sizeof(p->cin)) == -1)
				{
					perror("sendto error");
					return -1;
				}
				p = p->next;
			}
			printf("**system**[%s %d]:chat成功\n",inet_ntoa(sin.sin_addr),ntohs(sin.sin_port));
		}
	}

	return 0;
}

客户端

#include <myhead.h>

struct msgTyp
{
	char type;  //L  C  Q
	char usrName[20];
	char msgText[1024];
};

int main(int argc, const char *argv[])
{
	struct msgTyp usr;

	int cfd = socket(AF_INET,SOCK_DGRAM,0);
	if(cfd == -1)
	{
		perror("socket error");
		return -1;
	}

	//判断是否写外部参数
	if(argc < 3)
	{
		printf("请输入IP和端口号\n");
		return -1;
	}

	//填写服务器信息
	struct sockaddr_in sin;
	sin.sin_family = AF_INET;
	sin.sin_port = htons(atoi(argv[2]));
	sin.sin_addr.s_addr = inet_addr(argv[1]);
	socklen_t addrlen = sizeof(sin);

	//输入姓名
	char name[20] = "";
	printf("请输入姓名>>>>");
	fgets(name,sizeof(name),stdin);
	name[strlen(name)-1] = '\0';

	usr.type = 'L';
	strcpy(usr.usrName,name);
	if(sendto(cfd,&usr,sizeof(usr),0,(struct sockaddr*)&sin,sizeof(sin)) == -1)
	{
		perror("sendto error");
		return -1;
	}

	//定义一个文件描述符,将检测的文件描述符放入集合
	fd_set readfds,tempfds;

	FD_ZERO(&readfds);

	FD_SET(0,&readfds);
	FD_SET(cfd,&readfds);

	int maxfd = cfd;  //记录最大的文件描述符

	while(1)
	{
		tempfds = readfds;

		int res = select(maxfd+1,&tempfds,NULL,NULL,NULL);
		if(res == -1)
		{
			perror("select error");
			return -1;
		}
		
		//收到客户端信息
		if(FD_ISSET(cfd,&tempfds))
		{
			bzero(usr.msgText,sizeof(usr.msgText));
			if(recvfrom(cfd,usr.msgText,sizeof(usr.msgText)-1,0,(struct sockaddr*)&sin,&addrlen) == -1)
			{
				perror("recvfrom error");
				return -1;
			}
			printf("%s\n",usr.msgText);
		}

		//发送数据
		if(FD_ISSET(0,&tempfds))
		{
			bzero(usr.msgText,sizeof(usr.msgText));
			fgets(usr.msgText,sizeof(usr.msgText),stdin);
			usr.msgText[strlen(usr.msgText)-1] = '\0';

			//退出操作
			if(strcmp(usr.msgText,"quit") == 0)
			{
				usr.type = 'Q';
				sendto(cfd,&usr,sizeof(usr),0,(struct sockaddr*)&sin,addrlen);
				close(cfd);
				return 0;
			}
			//聊天操作
			else 
			{
				usr.type = 'C';
				if(sendto(cfd,&usr,sizeof(usr),0,(struct sockaddr*)&sin,addrlen) == -1)
				{
					perror("sendto error");
					return -1;
				}
			}
		}
	}
	return 0;
}

 结果

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

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

相关文章

四年蓄势,TikTok决定硬刚

在X平台&#xff08;原推特&#xff09;上线的一则视频里&#xff0c;周受资看起来又焦急&#xff0c;又强硬。他的眉毛扭到了一起&#xff0c;完全不像去年那个在美国国会听证会上&#xff0c;接受了5小时高压问询&#xff0c;仍风度翩翩的跨国公司CEO。 “过去几年来&#x…

js数据流详细讲解

文章目录 单向数据流单向数据流示例: 双向数据流双向数据流示例: 延伸和扩展状态管理Redux 示例&#xff1a; 异步数据流异步操作示例&#xff08;使用 async/await&#xff09;&#xff1a; 数据转换和处理数据处理示例&#xff08;使用 lodash&#xff09;&#xff1a; 实时数…

解决大型多模态模型的幻觉问题,新方法AITuning助力AI更可靠

引言&#xff1a;多模态对话幻觉的挑战 在人工智能领域&#xff0c;开发能够通过视觉和语言等多种渠道与人类互动的通用助手是一个重要问题。受到大型语言模型&#xff08;LLMs&#xff09;如ChatGPT的显著成功的启发&#xff0c;研究社区对开发能够支持视觉-语言指令的多模态助…

力扣热门算法题 75. 颜色分类,76. 最小覆盖子串,77. 组合

75. 颜色分类&#xff0c;76. 最小覆盖子串&#xff0c;77. 组合&#xff0c;每题做详细思路梳理&#xff0c;配套Python&Java双语代码&#xff0c; 2024.03.21 可通过leetcode所有测试用例。 目录 75. 颜色分类 解题思路 完整代码 Python Java 76. 最小覆盖子串 解…

六.排序nb三人组(快速排序)

目录 17-快速排序原理介绍 思路: 18-快速排序代码实现 19-快速排序代码实现2 缺点: 递归的限度: 17-快速排序原理介绍 思路: --先找一个变量把 5(第一个数) 存起来, (两个箭头分别是left , right) --左边有一个空位, 发现左边的位置是给比5小的值准备的. --找比5小的值…

校招应聘流程讲解

在整个应聘流程中&#xff0c;记得保持积极的态度、认真准备面试&#xff0c;同时也要对自己的能力和经验有清晰的认识&#xff0c;这样才能在竞争激烈的校园招聘中脱颖而出&#xff0c;成功获得心仪的工作机会. 1. 校招资源获取 想要参加校招&#xff0c;首先需要获取校招资…

ROS2从入门到精通0-3:VSCode 搭建 ROS2 工程环境

目录 0 专栏介绍1 Ubuntu下安装VSCode1.1 基本安装1.2 将VSCode添加到侧边栏 2 VSCode集成相关插件3 VSCode运行ROS2环境步骤3.1 安装编译依赖项3.2 创建工作空间和源码空间3.3 启动VSCode与配置 4 测试工程环境4.1 C版本4.2 Python版本 0 专栏介绍 本专栏旨在通过对ROS2的系统…

每日一题 --- 977. 有序数组的平方[力扣][Go]

今天这一题和昨天的知识点是一样的&#xff0c;就是双指针法。 题目&#xff1a; 给你一个按 非递减顺序 排序的整数数组 nums&#xff0c;返回 每个数字的平方 组成的新数组&#xff0c;要求也按 非递减顺序 排序。 示例 1&#xff1a; 输入&#xff1a;nums [-4,-1,0,3,1…

Java中调用由C/C++实现的本地库(JNI本地程序调用)

文章目录 背景介绍什么是JNI&#xff1f;什么是本地库&#xff1f;开发Java使用JNI本地库步骤 编写Java类实现JNI本地调用windows系统下编译动态链接库创建Java项目&#xff08;demo&#xff09;第一步&#xff1a;编写带有native的Java类第二步&#xff1a;javac生成NativeDem…

深度学习_微调_7

目标 微调的原理利用微调模型来完成图像的分类任务 微调的原理 微调&#xff08;Fine-tuning&#xff09;是一种在深度学习中广泛应用的技术&#xff0c;特别是在预训练模型&#xff08;Pretrained-Models&#xff09;的基础上进行定制化训练的过程。微调的基本原理和步骤如下…

CRM软件推荐2024:五款顶级产品解析,助您找到最佳选项!

一天之计在于晨&#xff0c;一年之计在于春。 2024年&#xff0c;民营经济发展继续壮大&#xff0c;这对于各行各业而言都是一种机遇挑战。企业想要规范化客户管理&#xff0c;实现销售增长&#xff0c;CRM软件仍然是一个不错的选择。在数字化时代&#xff0c;企业数字化转型已…

预防颈椎病,从职场健康做起

随着现代社会工作方式的转变&#xff0c;职场人士长时间伏案工作&#xff0c;颈椎病的发病率逐渐上升。本文将介绍一些实用的预防颈椎病的方法&#xff0c;帮助职场人士保持健康&#xff0c;提高工作效率。 一、了解颈椎病 颈椎病是指颈椎间盘退行性变及其继发性椎间关节病理性…

基于Python实现高德地图找房系统-爬虫分析

概要 针对大学毕业生对于工作地周边交通出行情况不了解、租房困难等问题,本文主要研究了厦门市的租房信息及地铁公交出行路线,利用Python爬虫爬取58同城上厦门市的租房信息,并进行处理分析,再通过高德地图API将房源信息展示在地图上,实现了基于高德地图API的租房地图。 关键词&…

基于Spring Boot技术的幼儿园管理系统

摘 要 随着信息时代的来临&#xff0c;过去的传统管理方式缺点逐渐暴露&#xff0c;对过去的传统管理方式的缺点进行分析&#xff0c;采取计算机方式构建幼儿园管理系统。本文通过课题背景、课题目的及意义相关技术&#xff0c;提出了一种活动信息、课程信息、菜谱信息、通知公…

Angular入门问题小本本

1、console.log打印object对象显示[object object] 解决方案&#xff1a;使用JSON.stringify console.log(JSON.stringify($rootScope.MaintainDeviceInfo));2、 State ‘goDiskManagement’’ is already defined 解决方案&#xff1a;同一个项目中&#xff0c;不能定义相同…

基于骨骼的动作识别的行动结构图卷积网络

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 摘要Abstract文献阅读&#xff1a;基于骨骼的动作识别的行动结构图卷积网络1、研究背景2、方法提出3、关键结构3.1、A-links inference module (AIM)3.2、Structura…

MyBatis3源码深度解析(二十)动态SQL实现原理(一)动态SQL的核心组件

文章目录 前言第八章 动态SQL实现原理8.1 动态SQL的使用8.1.1 \<if>8.1.2 <where|trim>8.1.3 <choose|when|otherwise>8.1.4 \<foreach>8.1.5 \<set> 8.2 SqlSource组件&BoundSql组件8.3 LanguageDriver组件8.3.1 XMLLanguageDriver8.3.2 Ra…

leetcode 20.有效的括号 JAVA

题目 思路 括号的匹配&#xff0c;这是一道经典的栈的应用问题。 给我们一个字符串&#xff0c;当我们遍历到左括号时&#xff0c;让其入栈。当我们遍历到右括号时&#xff0c;让栈顶元素出栈&#xff0c;看看栈顶的元素是否和遍历到的右括号匹配。不匹配的话直接false,匹配的…

vue2 脚手架

安装 文档&#xff1a;https://cli.vuejs.org/zh/ 第一步&#xff1a;全局安装&#xff08;仅第一次执行&#xff09; npm install -g vue/cli 或 yarn global add vue/cli 备注&#xff1a;如果出现下载缓慢&#xff1a;请配置npm 淘宝镜像&#xff1a; npm config set regis…

java算法第32天 | ● 122.买卖股票的最佳时机II ● 55. 跳跃游戏 ● 45.跳跃游戏II

122.买卖股票的最佳时机II 本题中理解利润拆分是关键点&#xff01; 不要整块的去看&#xff0c;而是把整体利润拆为每天的利润。假如第 0 天买入&#xff0c;第 3 天卖出&#xff0c;那么利润为&#xff1a;prices[3] - prices[0]。 相当于(prices[3] - prices[2]) (prices[…