UDP聊天室

1.头文件

/*===============================================
*   文件名称:UDP.h
*   创 建 者:crx    
*   创建日期:2023年09月3日
*   描    述:
================================================*/
#ifndef _UDP_H
#define _UDP_H#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>  
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>typedef struct node{            //链表节点保存用户地址结构体信息struct sockaddr_in caddr;  struct node *next;   
}Node,*Pnode;typedef struct mesg{          //用户状态、姓名、消息char state;  char name[20];  char text[60];  
}Mesg;enum state{         //状态:登录、转发、下线Login,  Relay,   Quit,   
};//创建头节点
Pnode create_node();
//插入,登录
int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg);
//转发
void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg);
//删除,下线
int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg);#endif

2.服务器

/*===============================================*   文件名称:UDPs.c*   创 建 者:crx     *   创建日期:2023年09月3日*   描    述:================================================*/
#include "UDP.h"int main(int argc, char *argv[])
{//1.创建套接字int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");return -1;}//2.绑定struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(8181);saddr.sin_addr.s_addr = INADDR_ANY;int bindfd = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));if(-1 == bindfd){perror("bind");return -1;}//3.准备保存客户端地址结构体,等待登录printf("等待登录....\n");struct sockaddr_in caddr;               socklen_t addrlen = sizeof(caddr);Mesg msg;//4.创建头节点Pnode p = create_node();    Pnode q = p;Pnode temp = p;while(1){memset(&caddr,0,sizeof(caddr));  //5.接收用户登录信息recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&addrlen); //6.根据用户状态执行对应操作//msg.state = Login
//用户登录,链表插入用户信息
//判断链表是否为空,为空则插入用户
//链表不为空,判断是否是链表中已有用户,不是则插入用户信息
//转发登录消息给其他在线用户if(msg.state == Login)     {if(NULL == q->next){           insert_node(p,caddr,msg);   strcpy(msg.text,"已登录!");}else{   temp = p->next;while(temp){        if(temp->caddr.sin_port == caddr.sin_port && temp->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr)break;        elsetemp = temp->next;}if(NULL == temp){insert_node(p,caddr,msg);strcpy(msg.text,"已登录!");relay(sockfd,p,caddr,msg);}}}//msg.state = Relay
//转发用户信息给其他在线用户if(msg.state == Relay)   {relay(sockfd,p,caddr,msg);}//msg.state = Quit
//用户下线
//链表中删除用户信息
//转发用户下线信息给其他用户if(msg.state == Quit)        {delete_node(p,caddr,msg);strcpy(msg.text,"已下线");relay(sockfd,p,caddr,msg);}}return 0;
} //创建头节点
Pnode create_node()
{            Pnode p = (Pnode)malloc(sizeof(Node));if(NULL == p){perror("malloc");return NULL;}p->next = NULL;return p;
}//插入,登录
int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg)
{ if(NULL == p){return -1;}Pnode new = (Pnode)malloc(sizeof(Node));if(NULL == new){perror("malloc");return -2;}new->next = p->next;p->next = new;new->caddr = caddr;printf("已登录!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));return 1;
}//转发
void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg)        {while(p->next){    p = p->next;if(p->caddr.sin_port == caddr.sin_port && p->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr){continue;    }else{sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr)); }}
}//删除,下线
int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg)  
{if(NULL == p){return -1;}while(p->next){if(memcmp(&(p->next->caddr),&caddr,sizeof(caddr)) == 0){Pnode q = p->next;p->next = q->next;free(q);break;}else{p = p->next;}}printf("已下线!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
}

3.客户端

/*===============================================*   文件名称:UDPc.c*   创 建 者:crx     *   创建日期:2023年09月3日*   描    述:================================================*/
#include "UDP.h"int main(int argc, char *argv[])
{//1.创建套接字int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");return -1;}//2.服务器地址struct sockaddr_in saddr;   saddr.sin_family = AF_INET;saddr.sin_port = htons(8181);saddr.sin_addr.s_addr = inet_addr("192.168.17.225");//3.创建用户Mesg msg;    //4.运行后触发msg.state = Login//登录填写用户名//发送给服务器登录信息转发登录消息操作printf("登录\n");   msg.state = Login;printf("请输入用户名:\n");fgets(msg.name,20,stdin);printf("******************************************\n");if(msg.name[strlen(msg.name)-1] == '\n')msg.name[strlen(msg.name) -1] = '\0';//发送用户登录消息if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))) {perror("sendto");return -1;}//5.创建子进程pid_t pid = fork();//6.子进程循环接收其他用户消息并打印发送人及信息if(pid == 0)  {while(1){socklen_t addrlen = sizeof(saddr);recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,&addrlen);printf("~%s~ : %s\n",msg.name,msg.text);}} else{//7.父进程获取用户终端输入到用户消息中while(1){fgets(msg.text,sizeof(msg.text),stdin);    if(msg.text[strlen(msg.text)-1] == '\n')msg.text[strlen(msg.text) -1] = '\0';//8.处理终端输入//终端输入Quit则触发msg.state = Quit
//发送给服务器下线信息执行对应操作
//使用SIGKILL强制结束进程if(strcmp(msg.text,"Quit") == 0)  {msg.state = Quit;if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))){perror("sendto");return -1;}kill(pid,SIGKILL); wait(NULL);exit(0);}
//终端输入不是Quit则触发msg.state = Relay
//发送给服务端执行转发操作else{msg.state = Relay;  }if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))){perror("sendto");return -1;}}}close(sockfd);return 0;
}

4.makefile

all:UDPs UDPc
UDPs:UDPs.cgcc  UDPs.c -o UDPs
UDPc:UDPc.cgcc  UDPc.c -o UDPc
clean:rm UDPs UDPc

5.结果

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

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

相关文章

Unity 之 Material (材质)渲染3D对象的重要组件

文章目录 介绍一些代码例子 介绍 在Unity中&#xff0c;Material&#xff08;材质&#xff09;是一种用于渲染3D对象的重要组件。Material定义了对象的外观&#xff0c;包括其颜色、纹理、光照属性和反射等。以下是关于Material的详细介绍&#xff1a; 创建Material&#xff1…

云计算时代的采集利器

大家好&#xff01;在今天的知识分享中&#xff0c;我们将探讨一个在云计算环境中的爬虫应用利器——独享IP。如果你是一名爬虫程序员&#xff0c;或者对数据采集和网络爬虫有浓厚的兴趣&#xff0c;那么这篇文章将向你展示独享IP在云计算环境下的应用价值。 1. 什么是独享IP&…

冠达管理:元宇宙三年行动计划发布,高增长潜力股名单出炉

未来5年&#xff0c;国内元国际商场规划至少打破2000亿元大关。 金融监管总局9月10日发布《关于优化保险公司偿付能力监管规范的告诉》&#xff0c;优化保险公司偿付能力监管规范&#xff0c;自发布之日起施行。 金融监管总局释放重要利好&#xff0c;引导保险资金更大力度地…

ClickHouse 存算分离改造:小红书自研云原生数据仓库实践

ClickHouse 作为业界性能最强大的 OLAP 系统&#xff0c;在小红书内部被广泛应用于广告、社区、直播和电商等多个业务领域。然而&#xff0c;原生 ClickHouse 的 MPP 架构在运维成本、弹性扩展和故障恢复方面存在较大局限性。为应对挑战&#xff0c;小红书数据流团队基于开源 C…

四叶草clover配置工具:Clover Configurator for Mac

Clover Configurator是一款Mac上的工具&#xff0c;用于配置和优化Clover引导加载器。Clover引导加载器是一种用于启动macOS的开源引导加载器。它允许用户在启动时选择操作系统和配置启动选项。 Clover Configurator提供了一个可视化的界面&#xff0c;让用户可以轻松地编辑和…

PlantUML入门教程:画时序图

软件工程中会用到各种UML图&#xff0c;例如用例图、时序图等。那我们能不能像写代码一样去画图呢&#xff1f; 今天推荐一款软件工程师的作图利器--PlantUML&#xff0c;它能让你用写代码的方式快速画出UML图。 一、什么是PlantUML&#xff1f; PlantUML是一个允许你快速作出…

【Ubuntu搭建MQTT Broker及面板+发布消息、订阅主题】

Ubuntu搭建MQTT Broker及面板发布消息、订阅主题 配置curl数据源 curl -s https://assets.emqx.com/scripts/install-emqx-deb.sh | sudo bash开始安装 sudo apt-get install emqx启动 sudo emqx start使用面板 根据自己的服务器是否开始了防火墙放行端口&#xff08;1808…

2023工博会,正运动机器视觉运动控制一体机应用预览(二)

展会倒计时&#xff1a;7天 本次的中国国际工业博览会正运动技术将携高性能x86平台Windows实时视觉运动控制器VPLC711亮相。 •运动控制机器视觉一站式开发&#xff0c;缩短开发周期&#xff0c;降低硬件成本&#xff1b; •可替代传统的工控机运动控制卡/PLC视觉软件的自动化…

平衡二叉搜索树(AVL)——【C++实现插入、删除等操作】

本章完整代码gitee地址&#xff1a;平衡二叉搜索树 文章目录 &#x1f333;0. 前言&#x1f332;1. AVL树概念&#x1f334;2. 实现AVL树&#x1f33f;2.1 结构定义&#x1f33f;2.2 插入&#x1f490;左单旋&#x1f490;右单旋&#x1f490;左右双旋&#x1f490;右左双旋 &a…

TypeScript:赋予JavaScript数据类型新的力量,提升编程效率!

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! ​ &#x1f4da; 前言 TypeScript&#xff1a;扩展JavaScript数据类型&#xff0c;赋予编程更强大的表达能力&#xff01…

数据挖掘实验-主成分分析与类特征化

数据集&代码https://www.aliyundrive.com/s/ibeJivEcqhm 一.主成分分析 1.实验目的 了解主成分分析的目的&#xff0c;内容以及流程。 掌握主成分分析&#xff0c;能够进行编程实现。 2.实验原理 主成分分析的目的 主成分分析就是把原有的多个指标转化成少数几个代表…

Kafka3.0.0版本——消费者(Sticky分区分配策略以及再平衡)

目录 一、Sticky分区分配策略原理二、Sticky分区分配策略 示例需求三、Sticky分区分配策略代码案例3.1、创建带有7个分区的sevenTopic主题3.2、创建三个消费者 组成 消费者组3.3、创建生产者3.4、测试3.5、Sticky分区分配策略代码案例说明 四、Sticky分区分配再平衡案例4.1、停…

Redis 删除策略

文章目录 Redis 删除策略一、过期数据二、数据删除策略1、定时删除2、惰性删除3、定期删除4、删除策略对比 三、逐出算法 Redis 删除策略 一、过期数据 Redis是一种内存级数据库&#xff0c;所有数据均存放在内存中&#xff0c;内存中的数据可以通过TTL指令获取其状态 XX &a…

【李自然说】在创业路演现场,3分钟打动投资人 (notebook)[Updating]

【李自然说】在创业路演现场&#xff0c;3分钟打动投资人_哔哩哔哩_bilibili 融资的核心问题&#xff08;三分钟内讲清楚&#xff09; - 竞争者做什么&#xff0c;我们做什么 &#xff08;是否有&#xff0c;没有那潜在competitor是谁&#xff0c;有没有可能变成合作伙伴&#…

构建高效实时数据流水线:Flink、Kafka 和 CnosDB 的完美组合

当今的数据技术生态系统中&#xff0c;实时数据处理已经成为许多企业不可或缺的一部分。为了满足这种需求&#xff0c;Apache Flink、Apache Kafka和CnosDB等开源工具的结合应运而生&#xff0c;使得实时数据流的收集、处理和存储变得更加高效和可靠。本篇文章将介绍如何使用 F…

java的动态代理如何实现

一. JdkProxy jdkproxy动态代理必须基于接口(interface)实现 接口UserInterface.java public interface UserService {String getUserName(String userCde); }原始实现类&#xff1a;UseServiceImpl.java public class UserServiceImpl implements UserSerice {Overridepub…

举例说明PyTorch函数torch.cat与torch.stack的区别

一、torch.cat与torch.stack的区别 torch.cat用于在给定的维度上连接多个张量&#xff0c;它将这些张量沿着指定维度堆叠在一起。 torch.stack用于在新的维度上堆叠多个张量&#xff0c;它会创建一个新的维度&#xff0c;并将这些张量沿着这个新维度堆叠在一起。 二、torch.…

原生js之dom表单改变和鼠标常用事件

那么好,本次我们聊聊表单改变时如何利用onchange方法来触发input改变事件以及鼠标常用的滑入滑出,点击down和点击up事件. 关于onchange方法 onchange方法在鼠标输入完后点击任何非输入框位置时触发.触发时即可改变原有输入框的值. out 、leave、over、down、up鼠标方法 当用…

React refers to UMD global, but the current file is a module vite初始化react项目

vite搭建react项目 初始化项目 npm create vite 在执行完上面的命令后&#xff0c;npm 首先会自动下载create-vite这个第三方包&#xff0c;然后执行这个包中的项目初始化逻辑。输入项目名称之后按下回车&#xff0c;此时需要选择构建的前端框架&#xff1a; ✔ Project na…

932. 漂亮数组

932. 漂亮数组 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 932. 漂亮数组 https://leetcode.cn/problems/beautiful-array/description/ 完成情况&#xff1a; 解题思路&#xff1a; nums 是由范围 [1, n] 的…