UDP实现聊天室

现象:

源码:

服务器:

#include<myhead.h>

struct sockaddr_in serveraddr,caddr;
enum type_t//枚举
{
	Login,
	Chat,
	Quit,
};
typedef struct MSG
{
	char type;//L C Q
	char name[32];//
	char text[128];//
}msg_t;

typedef struct NODE//链表
{
	struct sockaddr_in caddr;
	struct NODE *next;
}node_t;

node_t *create_node(void)//建头节点
{
	node_t *p=(node_t *)malloc(sizeof(node_t));
	if(p==NULL)
	{
		perror("malloc err");
		return NULL;
	}
	p->next=NULL;
	return p;

}
void do_login(int ,msg_t ,node_t *,struct sockaddr_in);//登录的函数
void do_chat(int ,msg_t ,node_t *,struct sockaddr_in);//群聊的函数
void do_quit(int ,msg_t ,node_t *,struct sockaddr_in);//退出函数
int main(int argc, char const *argv[])
{
	if(argc !=3)
	{
		printf("Usage:./a.out <port>\n");
		return -1;
	}
	//创建UDP套接字
	int sockfd = socket(AF_INET,SOCK_DGRAM,0);
	if(sockfd<0)
	{
		perror("socket err");
		exit(-1);
	}
	//填充服务器网络信息结构体
	serveraddr.sin_family=AF_INET;
	serveraddr.sin_port=htons(atoi(argv[2]));

	serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
	socklen_t len = sizeof(caddr);
	//定义保存客户端网络信息的结构体
	//绑定套接字和服务器网络信息的结构体
	bind(sockfd,(struct sockaddr *)&serveraddr,sizeof(serveraddr));
	printf("bind ok!\n");
	msg_t msg;
	node_t *p=create_node();
	while(1)
	{
		if(recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&len)<0)
		{
			perror("recvfrom err");
			return -1;
		}
		if(msg.type==Login)
		{
			strcpy(msg.text,"已上线");
			printf("ip:%s pord:%d name:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),msg.name);
			printf("状态:%s\n",msg.text);
			do_login(sockfd,msg,p,caddr);
		}
		else if(msg.type==Chat)
		{
			do_chat(sockfd,msg,p,caddr);    
		}
		else if(msg.type==Quit)
		{
			strcpy(msg.text,"已下线");
			printf("ip:%s pord:%d name:%s\n",inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port),msg.name);
			printf("状态:%s\n",msg.text);
			do_quit(sockfd,msg,p,caddr);        
		}
	}
	close(sockfd);
	return 0;
}
//登录的函数
//功能:
//1》将新登录的用户转发给所有已经登录的用户(遍历链表发送谁登录的消息)
//2》创建新节点来保存新登录用户的信息,链接到链表尾就可已
void do_login(int sockfd,msg_t msg,node_t *p,struct sockaddr_in caddr)
{

	sprintf(msg.text,"%s 已上线",msg.name);
	while(p->next != NULL)
	{
		p= p->next;
		sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		//printf("%s\n",msg.text);
	}
	node_t *new=(node_t *)malloc(sizeof(node_t));
	//初始化
	new->caddr=caddr;
	new->next=NULL;
	//链接到链表尾
	p->next=new;
	return;
}
//群聊的函数
//功能:将客户端发来的聊天内容转发给所有已登录的用户,除了发送聊天内容的用户已外
void do_chat(int sockfd,msg_t msg,node_t *p,struct sockaddr_in caddr)
{
	//遍历链表
	while(p->next != NULL)
	{
		p=p->next;

		if(memcmp(&(p->caddr),&caddr,sizeof(caddr)) != 0)
		{
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		}
	}
	return;
}
//退出函数
//功能:
//1》将谁退出的消息转发给i所有用户
//2》将链表中保存这个推出的用户信息的节点删除
void do_quit(int sockfd,msg_t msg,node_t *p,struct sockaddr_in caddr)
{
	sprintf(msg.text,"%s 已下线",msg.name);
	while(p->next != NULL)
	{
		if((memcmp(&(p->next->caddr),&caddr,sizeof(caddr)))==0)
		{ 
			node_t *dele=NULL;
			dele = p->next;
			p->next=dele->next;
			free(dele);
			dele=NULL;
		}
		else
		{
			p=p->next;
			sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr));
		}  
	}
	return;
}

客户端:

#include <myhead.h>

enum type_t
{
    Login,
    Chat,
    Quit,
};
typedef struct 
{
    char type;//L C Q
    char name[32];//
    char text[128];//
}msg_t;

int main(int argc, char const *argv[])
{
     if(argc !=3)
    {
        printf("Usage ./a.out <ip> <port>\n");
        return -1;
    }
   
    int sockfd = socket(AF_INET,SOCK_DGRAM,0);
    if(sockfd<0)
    {
        perror("socket err");
        exit(-1);
    }
    struct sockaddr_in serveraddr;
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(atoi(argv[2]));
    serveraddr.sin_addr.s_addr=inet_addr(argv[1]);
    socklen_t len = sizeof(serveraddr);
    msg_t msg;
    //先执行登录操作 
    printf("请登录:\n");
    msg.type=Login;
    printf("请输入用户名:");
    fgets(msg.name,32,stdin);
    if(msg.name[strlen(msg.name)-1]=='\n')
       msg.name[strlen(msg.name)-1]='\0';
    //发送登录消息
    if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,len)<0)
       {
         perror("sendto err");
         exit(-1);
       }
    pid_t pid=fork();
     if(pid<0)
    {
        perror("fork err");
        exit(-1);
    }
    else if(pid==0)
    {
        while(1)
        {
            if(recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL)<0)
            {
                perror("recvfrom err");
                return -1;
            }
            printf("[%s]:%s\n",msg.name,msg.text);
        } 
    }    
    else 
    {
        while(1)
        {
            fgets(msg.text,sizeof(msg.text),stdin);
            if(msg.text[strlen(msg.text)-1]=='\n')
               msg.text[strlen(msg.text)-1]='\0';
            if(strcmp(msg.text,"quit")==0)
            {
                msg.type=Quit; 
                sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,len);
                kill(pid,SIGKILL);
                wait(NULL);
                exit(-1);
            }else
        {
            msg.type=Chat;
        }
        //发送消息
        sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&serveraddr,len);
        }
    }
    close(sockfd);
    return 0;
}

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

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

相关文章

【C语言基础】:内存操作函数

文章目录 一、memcpy函数的使用和模拟实现1.1 memcpy函数的使用1.2 memcpy函数的模拟实现 二、memmove函数的使用和模拟实现2.1 memmove函数的使用2.2 memmove函数的模拟实现 三、memset函数的使用3.1 menset函数的使用 四、memcmp函数的使用4.1 memcmp函数的使用 学海无涯苦作…

HarmonyOS模拟器调试

1 、设置 -> 系统设置 -> 关于手机 快速点击 5 次 HarmonyOS 版本开启开发者模式。 2 、设置 -> 系统和更新 -> 开发人员选项 到开发人员选项后往下拉有 USB 调试 &#xff0c;把 USB 调试开关打开。 源自&#xff1a;HarmonyOS HarmonyOS Next 仿小米商城App入门…

Prompt提示工程上手指南:基础原理及实践(四)-检索增强生成(RAG)策略下的Prompt

前言 此篇文章已经是本系列的第四篇文章&#xff0c;意味着我们已经进入了Prompt工程的深水区&#xff0c;掌握的知识和技术都在不断提高&#xff0c;对于Prompt的技巧策略也不能只局限于局部运用而要适应LLM大模型的整体框架去进行改进休整。较为主流的LLM模型框架设计可以基…

iOS - Runtime-isa详解(位域、union(共用体)、位运算)

文章目录 iOS - Runtime-isa详解&#xff08;位域、union&#xff08;共用体&#xff09;、位运算&#xff09;前言1. 位域介绍1.1 思路1.2 示例 - 结构体1.3 示例 - union&#xff08;共用体&#xff09;1.3.1 说明 1.4 结构体 对比 union&#xff08;共用体&#xff09; 2. a…

Selenium 自动化 —— 切换浏览器窗口

更多内容请关注我的 Selenium 自动化 专栏&#xff1a; 入门和 Hello World 实例使用WebDriverManager自动下载驱动Selenium IDE录制、回放、导出Java源码浏览器窗口操作 平时我们在使用浏览器时&#xff0c;通常会打开多个窗口&#xff0c;然后再多个窗口中来回切换&#xf…

[STM32] 使用 STM32CubeMX 创建 STM32 工程模板

STM32CubeMX 创建工程模板 跟着100ASK_STM32F103_MINI用户手册V1.1.pdf第7章的步骤&#xff0c;使用STM32CubeMX为STM32F103C8T6创建工程模板。 点击“ACCESS TO MCU SELECTOR”通过选择芯片创建工程&#xff0c;如下图所示 等待下载完成&#xff0c;如下图所示 在搜索框输入“…

矩阵螺旋输出

问题描述&#xff1a; 所谓螺旋矩阵&#xff0c;顾名思义&#xff0c;就是将矩阵元素以螺旋顺序输出&#xff0c;如图&#xff1a; 解决思路&#xff1a; 由图不难发现&#xff0c;整个螺旋输出过程是一个个左下右上遍历的循环&#xff0c;只是遍历的规模在越变越小&#xff…

【vscode打开多文件夹】

1)将文件夹添加到工作空间中 2)文件夹方式展开 3)最终效果 小技巧&#xff1a; 文件夹的位置不对的话&#xff0c;可以拖动进行调整。

【NLP笔记】预训练+Prompt Tuning新范式之LLM时代(GPT3...)

文章目录 概述GPT3 【参考链接】 一张图总结大语言模型的技术分类、现状和开源情况 大语言模型LLM微调技术&#xff1a;Prompt Tuning A Survey of Large Language ModelsThe Practical Guides for Large Language ModelsGPT3&#xff1a;Language Models are Few-Shot Learner…

鸿蒙开发案例:【图像加载缓存库ImageKnife】

专门为OpenHarmony打造的一款图像加载缓存库&#xff0c;致力于更高效、更轻便、更简单。 简介 OpenHarmony的自研版本&#xff1a; 支持内存缓存&#xff0c;使用LRUCache算法&#xff0c;对图片数据进行内存缓存。支持磁盘缓存&#xff0c;对于下载图片会保存一份至磁盘当…

视频汇聚平台EasyCVR启用图形验证码之后调用login接口的操作方法

视频综合管理平台EasyCVR视频监控系统支持多协议接入、兼容多类型设备&#xff0c;平台可以将区域内所有部署的监控设备进行统一接入与集中汇聚管理&#xff0c;实现对监控区域的实时高清视频监控、录像与存储、设备管理、云台控制、语音对讲、级联共享等&#xff0c;在监控中心…

Oracle 19C RAC集群补丁升级

文章目录 一、补丁包概述二、OPatch检查和更新Grid用户更新OPatchOracle用户更新OPatch 三、验证Oracle Inventory的有效性四、运行 OPatch 冲突检查五、运行opatch命令检查GI HOME下是否有足够的空间六、补丁冲突检测与解决&#xff08;修补程序&#xff09;七、使用root用户应…

聚观早报 | 滴滴2023年Q4营收;微软推广Copilot

聚观早报每日整理最值得关注的行业重点事件&#xff0c;帮助大家及时了解最新行业动态&#xff0c;每日读报&#xff0c;就读聚观365资讯简报。 整理丨Cutie 3月25日消息 滴滴2023年Q4营收 微软推广Copilot 极狐汽车将出口西班牙 华为公开智能驾驶新专利 华为P70系列发布…

数据挖掘终篇!一文学习模型融合!从加权融合到stacking, boosting

模型融合&#xff1a;通过融合多个不同的模型&#xff0c;可能提升机器学习的性能。这一方法在各种机器学习比赛中广泛应用&#xff0c; 也是在比赛的攻坚时刻冲刺Top的关键。而融合模型往往又可以从模型结果&#xff0c;模型自身&#xff0c;样本集等不同的角度进行融合。 数据…

辅助功能IOU(交并比)_3.2

实现两个目标框的交并比候选框在多目标跟踪中的表达方式及相应转换方法 IOU(Intersection over Union)&#xff0c;“交并比”&#xff0c;是计算机视觉和图像处理中常用的一个评价指标&#xff0c;尤其在目标检测任务中用来衡量模型预测的目标框与真实目标框的重合程度。 具体…

GuLi商城-商品服务-API-三级分类-查询-树形展示三级分类数据

1、网关服务配置路由 2、商品服务 3、启动本地nacos&#xff0c;打开nacos地址看nacos服务列表 4、编写VUE <template> <el-tree :data"menus" :props"defaultProps" node-click"handleNodeClick"></el-tree> </template…

计算机网络:物理层 - 传输媒体

计算机网络&#xff1a;物理层 - 传输媒体 物理层基本概念导引型传输媒体同轴电缆双绞线光纤 非引导型传输媒体无线电波微波红外线 物理层基本概念 在计算机网络中用来连接各种网络设备的传输媒体&#xff0c;种类众多&#xff0c;大致可以分为两类&#xff0c;一类是导引型传…

零基础入门数据挖掘系列之「特征工程」

摘要&#xff1a;对于数据挖掘项目&#xff0c;本文将学习应该从哪些角度做特征工程&#xff1f;从哪些角度做数据清洗&#xff0c;如何对特征进行增删&#xff0c;如何使用PCA降维技术等。 特征工程&#xff08;Feature Engineering&#xff09;对特征进行进一步分析&#xf…

数字乡村战略实施:科技引领农村经济社会全面发展

随着信息技术的快速发展&#xff0c;数字化已经成为推动经济社会发展的重要力量。在乡村振兴战略的大背景下&#xff0c;数字乡村战略的实施成为了引领农村经济社会全面发展的关键。本文将从数字乡村战略的内涵、实施现状、面临挑战及未来展望等方面&#xff0c;探讨科技如何引…

分类模型评估:混淆矩阵与ROC曲线

1.混淆矩阵2.ROC曲线 & AUC指标 理解混淆矩阵和ROC曲线之前&#xff0c;先区分几个概念。对于分类问题&#xff0c;不论是多分类还是二分类&#xff0c;对于某个关注类来说&#xff0c;都可以看成是二分类问题&#xff0c;当前的这个关注类为正类&#xff0c;所有其他非关注…