网络聊天室

Ser.c

#include<myhead.h>
#define SER_IP "192.168.159.148"
#define SER_PORT 6666

//因为客户端发送给服务器的消息是不同类型,所以定义结构体比较方便
typedef struct msg_TYPE
{
	char type;                      //  L:登录  C:聊天  Q:退出
	char usrName[20];              //用户名
	char msgText[1024];           //消息正文
}msg_t;

//定义链表结构体:涉及到用户的登录和退出,也就是插入和删除,所以用链表比较方便
typedef struct Node
{
	//char usrName[20];      //用户名(数据域)
	struct sockaddr_in cin;    //IP地址和端口号(数据域)
	struct Node *next;        //指针域
}node_t;

//函数声明
void create_link(node_t **head);
int do_register(int sfd,msg_t msg,struct sockaddr_in cin,node_t *lhead);
int do_chat(int sfd,msg_t msg,struct sockaddr_in cin,node_t *lhead);
int quit_chat(int sfd,msg_t msg,struct sockaddr_in cin,node_t *lhead);

int main(int argc, const char *argv[])
{
	//判断终端输入是否合理
	if(argc!=3)
	{
		printf("input file error\n");
		printf("usage:./a.out IP port\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;
	memset(&sin,0,sizeof(sin));
	sin.sin_family=AF_INET;
	sin.sin_port=htons(atoi(argv[2]));
	sin.sin_addr.s_addr=inet_addr(argv[1]);
	socklen_t socklen1=sizeof(sin);

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

	//填充客户端地址信息结构体
	struct sockaddr_in cin;
	socklen_t socklen2=sizeof(cin);
	msg_t msg;    //定义结构体变量

	//创建多进程,父进程用来发送系统消息,子进程用来接收数据并处理
	pid_t pid=fork();
	if(pid>0)
	{
		//父进程:发送系统消息
		msg.type='C';
		strcpy(msg.usrName,"server");

		while(1)
		{
			fgets(msg.msgText,1024,stdin);
			msg.msgText[strlen(msg.msgText)-1]=0;
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&sin,socklen1)==-1)
			{
				perror("sendto error");
				return -1;
			}
		}
	}
	else if(pid==0)
	{
		//子进程:用来接收数据并处理
		//定义链表头节点
		node_t *lhead=NULL;
		create_link(&lhead);
		lhead->next=NULL;

		while(1)
		{
			//清空数据
			memset(&msg,0,sizeof(msg));
			memset(&cin,0,sizeof(cin));

			if((recvfrom(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&cin,&socklen2))==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			printf("%8s:[%s]\n",msg.usrName,msg.msgText);

			switch(msg.type)
			{
				case 'L':
					{
						do_register(sfd,msg,cin,lhead);
					}
					break;

				case 'C':
					{
						do_chat(sfd,msg,cin,lhead);
					}
					break;

				case 'Q':
					{
						quit_chat(sfd,msg,cin,lhead);
					}
					break;
			}
		}
	}
	else
	{
		perror("fork error");
		return -1;
	}
	//关闭套接字
	close(sfd);
	return 0;
}

//创建链表头节点
void create_link(node_t **head)
{
	*head=(node_t *)malloc(sizeof(node_t));
}

//用户登录
int do_register(int sfd,msg_t msg,struct sockaddr_in cin,node_t *lhead)
{
	//遍历链表,将登录信息发送给其他在线用户
	node_t *p=lhead;
	while(p->next!=NULL)
	{
		p=p->next;
		if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&(p->cin),sizeof(p->cin))==-1)
		{
			perror("sendto error");
			return -1;
		}
	}

	//将登录信息插入链表(头插)
	//定义一个指针保存用户信息
	node_t *umsg=NULL;
	create_link(&umsg);
	umsg->cin=cin;
	umsg->next=lhead->next;
	lhead->next=umsg;

	return 0;
}

//定义聊天函数
int do_chat(int sfd,msg_t msg,struct sockaddr_in cin,node_t *lhead)
{
	//遍历链表,将消息发送给除自己外所以用户
	node_t *p=lhead;
	while(p->next!=NULL)
	{
		p=p->next;   //循环后移
		//判断链表中信息是否是自己,是自己就不发送信息
		if(memcmp(&(p->cin),&cin,sizeof(cin)));
		{
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&(p->cin),sizeof(p->cin))==-1)
			{
				perror("sendto error");
				return -1;
			}
		}
	}
	return 0;
}

//定义退出函数
int quit_chat(int sfd,msg_t msg,struct sockaddr_in cin,node_t *lhead)
{
	node_t *p=lhead;
	while(p->next!=NULL)
	{
		//判断链表客户端信息是否是自己,是自己就不发送,并且将自己的客户端信息在链表内删除
		if(memcmp(&(p->next->cin),&cin,sizeof(cin)))
		{
			p=p->next;    //循环后移
			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)(&p->cin),sizeof(p->cin))==-1)
			{
				perror("sendto error");
				return -1;
			}
		}
		else
		{
			node_t *s;
			s=p->next;
			p->next=s->next;
			s->next=NULL;
			free(s);
			s=NULL;
		}
	}
	return 0;
}

Cli.c

#include<myhead.h>
#define SER_IP "192.168.159.148"
#define SER_PORT 6666

//因为客户端发送给服务器的消息是不同类型,所以定义结构体比较方便
typedef struct msg_TYPE
{
	char type;             //  L:登录  C:聊天  Q:退出
	char usrName[20];     //用户名
	char msgText[1024];  //消息正文
}msg_t;


int main(int argc, const char *argv[])
{
	//判断终端输入是否合理
	if(argc!=3)
	{
		printf("input file error\n");
		printf("usage:./a.out IP port\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;
	sin.sin_family=AF_INET;
	sin.sin_port=htons(atoi(argv[2]));
	sin.sin_addr.s_addr=inet_addr(argv[1]);
	socklen_t socklen1=sizeof(sin);

	//给服务器发送登录信息数据包
	msg_t msg;
	//清空数据
	memset(&msg,0,sizeof(msg_t));
	printf("请输入用户名:");
	fgets(msg.usrName,20,stdin);
	msg.usrName[strlen(msg.usrName)-1]=0;

	strcpy(msg.msgText,"加入群聊");
	if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&sin,socklen1)==-1)
	{
		perror("sendto error");
		return -1;
	}

	//创建多进程,父进程用来发送系统消息,子进程用来接收数据并处理
	pid_t pid=fork();
	if(pid>0)
	{
		//父进程:发送系统消息
		while(1)
		{
			msg.type='C';
			fgets(msg.msgText,128,stdin);
			msg.msgText[strlen(msg.msgText)-1]=0;

			if(strcmp(msg.msgText,"quit")==0)
			{
				msg.type='Q';
				strcpy(msg.msgText,"退出群聊");
			}

			if(sendto(sfd,&msg,sizeof(msg_t),0,(struct sockaddr*)&sin,socklen1)==-1)
			{
				perror("sendto error");
				return -1;
			}

			if(strcmp(msg.msgText,"退出群聊")==0)
			{
				break;
			}
		}
	}
	else if(pid==0)
	{
		//子进程:用来接收数据并处理
	
		while(1)
		{
			//清空数据
			memset(&msg,0,sizeof(msg));

			if((recvfrom(sfd,&msg,sizeof(msg_t),0,NULL,NULL))==-1)
			{
				perror("recvfrom error");
				return -1;
			}
			printf("%s:[%s]\n",msg.usrName,msg.msgText);	
		}
	}
	else
	{
		perror("fork error");
		return -1;
	}

	//给子进程发送一个退出信号
	kill(pid,SIGKILL);
	wait(NULL);

	//关闭套接字
	close(sfd);
	return 0;
}
	

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

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

相关文章

flowable的java class task,也叫服务任务

源码地址12级程序猿-新年正当红/flowable-ui和服务任务 启动flowable-ui-app 浏览器输入下面的地址 http://localhost:8080/flowable-ui/#/ 在服务任务这里设置java类的路径 com.dmg.flowabledemo.task.MyServiceTask 当请假任务完成之后&#xff0c;自动触发这个服务任务…

网络信息安全:nginx漏洞收集(升级至最新版本)

网络&信息安全&#xff1a;nginx漏洞收集&#xff08;升级至最新版本&#xff09; 一、风险详情1.1 nginx 越界写入漏洞(CVE-2022-41742)1.2 nginx 缓冲区错误漏洞(CVE-2022-41741)1.3 nginx 拒绝服务漏洞&#xff08;CNVD-2018-22806&#xff09; 二、nginx升级步骤 &…

奥壹oelove婚恋交友v10.0_10.1情感导师插件_商城插件SQL数据库导入升级方法

大家注意哈奥壹oelove的系统默认是不含情感导师插件和商城系统的&#xff0c;这两个插件需要再官方独立购买&#xff0c;有幸公司付钱购买了系统及两套商业插件&#xff0c;可以看我昵称找我注明CSDN我已经把数据库及模板文件提取出来了&#xff0c;先说下数据库把&#xff0c;…

基于Mindspore,通过Resnet50迁移学习实现猫十二分类

使用平台介绍 使用平台&#xff1a;启智AI协作平台 使用数据集&#xff1a;百度猫十二分类 数据集介绍 有cat_12_train和cat_12_test和train_list.txt train_list.txt内有每张图片所对应的标签 Minspore部分操作科普 数据集加载 Mindspore加载图片数据集就直接调整成这种…

uniapp H5 $el.querySelectorAll is not a function

在监听是否在可视区域遇到问题&#xff08;网页端&#xff09; 解决方案 <view class"container"> ...省略 业务代码... </view>参考 &#xff1a; https://blog.csdn.net/qq_18841969/article/details/134620559

狼人杀 (狼人) 个人理解玩法

今天 我们来说说 狼人杀游戏 每个板子都有的一个角色 狼人 因为 动物园板子 平民被换成了 羊驼 所以 狼人也是唯一一个所有板子都有的角色 狼人的技能非常简单 每天晚上 可以袭击一名玩家 如果没有特殊情况 被袭击的玩家天亮时会直接出局 特殊情况包括 比较典型的有 守卫的盾…

Matter 笔记1-环境准备,编译

不要远程登录Ubuntu输入以下命令&#xff0c;原因&#xff1a;ubuntu/linux上的http代理设置 1. 准备 1.1 工具 Ubuntu 22.04 LTSClash 里General的端口设置到ubuntu 的网络设置里 1.2 代码 这里使用芯科整理过的代码 git clone https://github.com/SiliconLabs/matter.…

Redis线程模型解析

引言 Redis是一个高性能的键值对&#xff08;key-value&#xff09;内存数据库&#xff0c;以其卓越的读写速度和灵活的数据类型而广受欢迎。在Redis 6.0之前的版本中&#xff0c;它采用的是一种独特的单线程模型来处理客户端的请求。尽管单线程在概念上似乎限制了其扩展性和并…

实验笔记之——Gaussian Splatting SLAM配置与测试

之前博客对基于3DGS的SLAM进行了调研 学习笔记之——3D Gaussian Splatting及其在SLAM与自动驾驶上的应用调研_3d gaussian splatting slam-CSDN博客文章浏览阅读3.2k次&#xff0c;点赞40次&#xff0c;收藏58次。论文主页3D Gaussian Splatting是最近NeRF方面的突破性工作&a…

腾讯云服务器运行yum检测超级慢问题

公司使用腾讯云服务器。最近买的几台服务器使用yum命令安装或 更新软件特别慢。如下图&#xff1a; 从图中看出网络速度极慢。 大约要等5-10分钟检测和更新配置完毕&#xff0c;进入到软件下载界面下载软件速度就快了。 琢磨了一下&#xff0c;连接慢并不是连接不上。查看yum…

第 125 场 LeetCode 双周赛题解

A 超过阈值的最少操作数 I 排序然后查找第一个大于等于 k 的元素所在的位置 class Solution { public:int minOperations(vector<int> &nums, int k) {sort(nums.begin(), nums.end());return lower_bound(nums.begin(), nums.end(), k) - nums.begin();} };B 超过阈…

后台组件-语言包

<groupId>org.qlm</groupId><artifactId>qlm-language</artifactId><version>1.0-SNAPSHOT</version> 平台提供多语言支持&#xff0c;以上为语言包&#xff0c;提供后台多语言支持。首批实现&#xff1a; public class LanguageConstan…

《操作系统真相还原》读书笔记二:环境搭建 xshell连接virtualbox

修改 sshd_config 使用 vi /etc/ssh/sshd_config命令进入sshd服务配置&#xff0c;键盘输入i进行编辑&#xff0c;将监听端口、监听地址前的 # 号去除&#xff0c;开启允许远程登录&#xff0c;开启使用用户名密码来作为连接验证。修改完成&#xff0c;按一下Esc&#xff0c;输…

【Godot4自学手册】第二十节增加游戏的打击感,镜头震颤、冻结帧和死亡特效

这节我主要学习增加游戏的打击感。我们通过镜头震颤、冻结帧、增加攻击点特效&#xff0c;增加死亡。开始了。 一、添加攻击点特效 增加攻击点特效就是&#xff0c;在攻击敌人时&#xff0c;会在敌人受击点显示一个受击动画。 1.添加动画。 第一步先做个受击点动画。切换到…

【数据结构】堆的TopK问题

大家好&#xff0c;我是苏貝&#xff0c;本篇博客带大家了解堆的TopK问题&#xff0c;如果你觉得我写的还不错的话&#xff0c;可以给我一个赞&#x1f44d;吗&#xff0c;感谢❤️ 目录 一. 前言二. TopK三. 代码 一. 前言 TOP-K问题&#xff1a;即求数据结合中前K个最大的元…

鸿蒙Harmony应用开发—ArkTS声明式开发(通用属性:背景设置)

设置组件的背景样式。 说明&#xff1a; 从API Version 7开始支持。后续版本如有新增内容&#xff0c;则采用上角标单独标记该内容的起始版本。 background10 background(builder: CustomBuilder, options?: { align?: Alignment }) 设置组件背景。 系统能力&#xff1a; …

外包干了2年,技术退步明显

先说一下自己的情况&#xff0c;研究生&#xff0c;19年进入广州某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试&#xf…

CCF CSP 202006-4 1246 (100分详细题解,矩阵乘法+快速幂)

202006-4 1246 &#xff08;100分详细题解&#xff0c;矩阵乘法快速幂&#xff09; 可以先看下csp官方的思路讲解&#xff0c;大思路是状态转移&#xff0c;先看下面s<2的情况 1 -> 2 2 -> 4 4 -> 16 6 -> 6 64 4 16 -> 26&#xff08;不考虑2&#xff0c;6…

“计算机界三大神书”之一 ——SICP【赠书活动】

目录 前言一、SICP简介二、改编本SCIP JS福利总结 前言 《计算机程序的构造和解释》&#xff08;Structure and Interpretation of Computer Programs&#xff0c;简记为SICP&#xff09;是MIT的基础课教材&#xff0c;出版后引起计算机教育界的广泛关注&#xff0c;对推动全世…

Java开发必须掌握,java高级工程师面试类的加载

前言 这些算法&#xff0c;都是小编一点一点看的大佬们的方法&#xff0c;自己积累的. 如果有什么描述的不对 点击领取2024完整开源项目《一线大厂Java面试题解析后端开发学习笔记最新架构讲解视频实战项目源码讲义》 的地方还望大佬赐教 多交流才能进步&#xff0c;加油&#…