网络聊天室的UDP实现以及数据库

网络聊天室UDP实现

服务器端:

头文件:

#include <myhead.h>//定义客户信息结构体
typedef struct magtye
{char type;            //消息类型char name[100];         //客户姓名char text[1024];  //客户发送聊天信息
}msg_t;//定义结构体存储每个客户端的ip地址和端口号
typedef struct IP_PORT
{struct sockaddr_in cin;//地址信息struct IP_PORT *next;//}*addrlist;void usr_login(int sfd,msg_t msg,addrlist *head,struct sockaddr_in cin);
void usr_chat(int sfd,msg_t msg,addrlist head,struct sockaddr_in cin);
void usr_quit(int sfd,msg_t msg,addrlist *head,struct sockaddr_in cin);

主函数:

#include"head.h"
int main(int argc, const char *argv[])
{//创建套接字int sfd=-1;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;}//服务器进行绑定//(1)、从终端获取端口号和地址char SER_IP[100];int SER_PORT;printf("请输入服务器ip地址和端口号:");scanf("%s %d",SER_IP,&SER_PORT);getchar();//吸收垃圾字符//(2)、填充服务器地址信息结构体struct sockaddr_in sin;sin.sin_family=AF_INET;           //地址族sin.sin_port=htons(SER_PORT);    //端口号sin.sin_addr.s_addr=inet_addr(SER_IP);  //IP地址      	socklen_t sin_len=sizeof(sin);//(3)、绑定if(bind(sfd,(struct sockaddr*)&sin,sin_len)==-1){perror("bind error");return -1;}//定义客户端网络信息结构体struct sockaddr_in cin;socklen_t cin_len=sizeof(cin);msg_t msg;//定义客户发送消息的机构体变量//创建父子进程处理不同的操作int pid=fork();if(pid==-1){perror("fork error");return -1;}if(pid==0)//字进程实现服务器接收消息类型{addrlist head=NULL;//链表头指针;while(1){memset(&msg,0,sizeof(msg));memset(&cin,0,sizeof(cin));//接收客户端发来的信息,并判断属于哪种消息类型recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&cin_len);switch(msg.type){case 'L':    //该消息类型代表新用户上线{//创建新节点保存新用户的ip地址和端口号				//向其他在线的用户发送新用户上线通知usr_login(sfd,msg,&head,cin);}break;case 'C':   //该消息类型代表一个用户发送消息给其他用户{usr_chat(sfd,msg,head,cin);}break;case 'Q':   //该消息类型代表一个用户下线{usr_quit(sfd,msg,&head,cin);}break;}}}else if(pid>0)//父进程实现服务器对客户端发送消息{strcpy(msg.name,"服务器消息");msg.type='C';while(1){memset(msg.text,0,sizeof(msg.text));fgets(msg.text,sizeof(msg.text),stdin);msg.text[strlen(msg.text)-1]='\0';sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len);if(strcmp(msg.text,"服务器下线")==0){sleep(1);break;}}kill(pid,SIGKILL);//服务器下线杀死子进程}wait(NULL);//关闭套接字close(sfd);return 0;
}

自定义函数:

#include"head.h"
//用户登录操作函数
void usr_login(int sfd,msg_t msg,addrlist *head,struct sockaddr_in cin)
{//1、创建新节点addrlist s=(addrlist)malloc(sizeof(addrlist));s->next=NULL;//存储新用户的ip地址和端口号printf("%s : %d\n",inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));s->cin=cin;s->next=*head;*head=s;//2、遍历链表将新用户上线消息发送给其他在线用户addrlist p=*head;while (p!=NULL){if(p->cin.sin_port!=cin.sin_port){sendto(sfd, &msg, sizeof(msg),0,(struct sockaddr *)&(p->cin), sizeof(p->cin));}p=p->next; //后移}printf("%s:%s\n",msg.name, msg.text);}//用户聊天操作函数
void usr_chat(int sfd,msg_t msg,addrlist head,struct sockaddr_in cin)
{addrlist p=head;while (p!=NULL){if(p->cin.sin_port!=cin.sin_port){sendto(sfd, &msg, sizeof(msg),0,(struct sockaddr *)&(p->cin), sizeof(p->cin));}p=p->next; //后移}}
//用户退出操作函数
void usr_quit(int sfd,msg_t msg,addrlist *head,struct sockaddr_in cin)
{printf("%s:%s\n",msg.name, msg.text);addrlist p=*head;addrlist del=NULL;while (p!=NULL){if(p->cin.sin_port!=cin.sin_port)  //向其他用户发送某个用户下线消息{sendto(sfd, &msg, sizeof(msg),0,(struct sockaddr *)&(p->cin), sizeof(p->cin));del=p;p=p->next;}else{sendto(sfd, &msg, sizeof(msg),0,(struct sockaddr *)&(p->cin), sizeof(p->cin));//向发出下线消息的用户回复消息if (del==NULL) {*head=p->next;} else {del->next=p->next;}free(del);del=NULL;break;}}
}

客户端:

#include <myhead.h>//定义客户信息结构体
typedef struct magtye
{char type;            //消息类型char name[100];         //客户姓名char text[1024];  //客户发送聊天信息
}msg_t;int main(int argc, const char *argv[])
{//创建套接字int cfd=-1;cfd=socket(AF_INET, SOCK_DGRAM, 0);if(cfd==-1){perror("socket error");return -1;}//将端口号快速重用int reuse=1;if(setsockopt(cfd,SOL_SOCKET,SO_REUSEADDR,&reuse,sizeof(reuse))==-1){perror("setsockopt error");return -1;}//(1)、从终端获取端口号和地址char SER_IP[100];int SER_PORT;printf("请输入服务器ip地址和端口号:");scanf("%s %d",SER_IP,&SER_PORT);getchar();//吸收垃圾字符//(2)、填充服务器地址信息结构体struct sockaddr_in sin;sin.sin_family=AF_INET;           //地址族sin.sin_port=htons(SER_PORT);    //端口号sin.sin_addr.s_addr=inet_addr(SER_IP);  //IP地址   socklen_t sin_len=sizeof(sin);msg_t msg;//客户端上线发送消息printf("请输入用户名:");fgets(msg.name,sizeof(msg.name),stdin);msg.name[strlen(msg.name)-1] = '\0';strcpy(msg.text,"已上线");msg.type='L';sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len);//创建多进程进行收发消息操作int pid=fork();if(pid==-1){perror("fork error");return -1;}if(pid>0)//父进程进行读取消息{while(1){recvfrom(cfd,&msg,sizeof(msg),0,NULL,NULL);if(strcmp(msg.text,"退出群聊")==0)    //用户自己下线{break;}printf("[%s]: %s\n", msg.name, msg.text);if(strcmp(msg.text,"服务器下线")==0) //服务器让客户端下线{kill(pid,SIGKILL);break;}}}else if(pid==0)//子进程发送消息{while(1){memset(msg.text,0,sizeof(msg.text));fgets(msg.text,sizeof(msg.text),stdin);//在终端获取聊天信息msg.text[strlen(msg.text)-1]='\0';if(strcmp(msg.text, "下线")==0){msg.type='Q';strcpy(msg.text, "退出群聊");}else{msg.type='C';}sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len);if(strcmp(msg.text,"退出群聊")==0){break;}}exit(EXIT_SUCCESS);}//关闭套接字回收子进程资源wait(NULL);   //阻塞回收子进程资源close(cfd);return 0;
}

思维导图:

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

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

相关文章

mysql的语法总结2

命令&#xff1a; mysql -u 用户名 -p mysql登录 命令&#xff1a;create database u1 创建数据库u1 查询数据库 使用数据库u1 创建表department 查询表department ALTER TABLE 表名 操作类型&#xff1b; 操作类型可以有以下的操作&#xff1a; 添加列&#x…

ZCC3808 低静态电流、可编程延迟监控电路 替代TPS3808

1 特性 • 上电复位发生器具有可调节延迟时间&#xff1a;1.25ms 至10s • 超低静态电流&#xff1a;2.4μA&#xff08;典型值&#xff09; • 高阈值精度&#xff1a;0.5% 典型值 • 提供适用于标准电压轨的 0.9V 至 5V 固定阈值电压且可调节电压低至 0.4V • 手动复位 …

CubeMX使用教程(2)——点亮LED

在上一章&#xff0c;我们完成了CubeMX的环境配置&#xff0c;这一章我们通过CubeMX来完成点亮LED的工作。 通过LED原理图可知&#xff0c;如果我们要点亮LD1&#xff08;第一个灯&#xff09;&#xff0c;它对应开发板的PC8端口&#xff0c;因此我们应该在CubeMX中将PC8配置为…

【并查集】一种简单而强大高效的数据结构

目录 一、并查集原理 二、并查集实现 三、并查集应用 1. LeetCode并查集相关OJ题 2. 并查集的其他应用及总结 一、并查集原理 并查集&#xff08;Disjoint Set&#xff09;是一种用来管理元素分组和查找元素所属组别的数据结构。它主要支持两种操作&#xff1a;查找&…

公司内部的手机拍照管理办法建议

公司内部的手机拍照管理是一项重要的工作&#xff0c;因为它涉及到公司的信息安全、知识产权保护和隐私保护等方面。以下是一些建议的公司内部手机拍照管理办法&#xff1a; 明确拍照目的和范围&#xff1a;首先&#xff0c;公司应明确员工使用手机拍照的目的和范围。例如&…

JavaScript进阶 (1)

封装 构造函数存在问题 js可以通过构造函数进行封装&#xff0c;但存在浪费内存问题 每创建新的对象引用数据类型就开辟新的空间 原型 构造函数通过原型分配函数是所有对象所共享的 每一个构造函数都有一个prototype属性&#xff0c;指向另一个对象&#xff0c;也称为原型…

小型内衣裤洗衣机哪个牌子好?四款高热度内衣洗衣机力荐

相信很多用户从小就有个观念&#xff0c;内衣裤不能跟其他衣物一起混合洗&#xff0c;否则会感染细菌&#xff0c;所以不少人的内衣裤一直都是自己手洗的&#xff0c;清洗内衣裤不算麻烦&#xff0c;但日常都要换洗&#xff0c;对一个白天上班已经很累的人来说&#xff0c;真是…

COM(Component Object Model)通信技术

COM&#xff08;Component Object Model&#xff09;通信技术是一种用于组件之间通信的二进制接口标准&#xff0c;它允许在不同进程或计算机上的组件进行交互。以下是 COM 通信技术的一些基本原理&#xff1a; 1. 二进制接口&#xff08;Binary Interface&#xff09;&#x…

如何 借助 AI + bat,1分钟内建立100个自定义文件和文件夹?

01 你好&#xff0c;我是云桃桃。 最近&#xff0c;我在写web系列的知识&#xff0c;做的过程中遇到过不少问题。今天&#xff0c;就来说说&#xff0c;我解决的一个批量新建文件/文件夹的问题。 事情是这样的。首先&#xff0c;我的大纲基本在幕布里已经弄好了&#xff0c;…

简析内部审计数字化转型的方法和路径【小落送书(第6期)】

个人名片&#xff1a; &#x1f43c;作者简介&#xff1a;一名大三在校生&#xff0c;喜欢AI编程&#x1f38b; &#x1f43b;‍❄️个人主页&#x1f947;&#xff1a;落798. &#x1f43c;个人WeChat&#xff1a;hmmwx53 &#x1f54a;️系列专栏&#xff1a;&#x1f5bc;️…

mysqld_exporter安装

1.介绍 主要监控Mysql数据库的稳定性、吞吐量、连接情况、缓冲池使用情况、查询性能等各项指标&#xff0c;是我们压测时常常需要监控的一些指标。2.安装 官方网站下载安装包&#xff0c;区分操作系统3.步骤 &#xff08;1&#xff09;直接解压 &#xff08;2&#xff09;在当…

基于ACM32 MCU的电动滑板车方案介绍

随着智能科技的快速发展&#xff0c;电动滑板车的驱动系统也得到了长足的发展。国内外的电动滑板车用电机驱动系统分为传统刷式电机和无刷电机两种类型。其中&#xff0c;传统的刷式电机已经逐渐被无刷电机所取代&#xff0c;无刷电机的性能和寿命都更出色&#xff0c;已成为电…

玩转AI大模型应用开发,轻松打造热门APPai数字人直播软件!

AI大模型应用在数字人直播领域的应用愈发成熟&#xff0c;为开发者提供了更多创意和可能性。数字人直播软件是当前热门的应用之一&#xff0c;它结合了虚拟主播和人工智能技术&#xff0c;为用户带来全新的互动体验。想要打造一个火爆的数字人直播软件&#xff0c;就需要玩转AI…

从0到1快速搭建一个jeecg 企业级应用管理后台

一. 基本介绍 官网地址&#xff1a;https://jeecg.com/ JeecgBoot 是一款企业级的低代码平台&#xff01;前后端分离架构 SpringBoot2.x&#xff0c;SpringCloud&#xff0c;Ant Design&Vue3&#xff0c;Mybatis-plus&#xff0c;Shiro&#xff0c;JWT 支持微服务。强大的…

vue 使用谷歌地图 @googlemaps/js-api-loader 进行模糊搜索

<template><div class"map"><div class"mapLeftStyle"><el-inputv-model"input"placeholder"请输入内容"class"controls"input"chnageinput"><i slot"prefix" class"e…

JavaWeb-MyBatis(上)

学完项目管理工具Maven后&#xff0c;继续学习MyBatis。我们都知道&#xff0c;JDBC是一个与数据库连接相关的API&#xff0c;最开始学习数据库连接都是从JDBC开始学起&#xff0c;但是其也有缺点&#xff0c;比如硬编码和操作繁琐等等。而今天学习的MyBatis就是专门为简化JDBC…

【Node.js从基础到高级运用】三、JavaScript基础

Node.js入门&#xff1a;JavaScript基础 在成功搭建了Node.js的开发环境之后&#xff0c;我们即将进入Node.js编程的核心——JavaScript语言本身。在这篇文章中&#xff0c;我们将回顾JavaScript的基础知识&#xff0c;这些是每个Node.js开发者都必须掌握的概念。我们还将探讨…

强制Unity崩溃的两个方法

在Unity中&#xff0c;这两种方法都可以用于强制使应用程序崩溃&#xff0c;但它们的作用略有不同&#xff1a; Application.ForceCrash(0); 这个方法会强制应用程序崩溃&#xff0c;并且参数传入的是一个整数值。当参数为0时&#xff0c;它会导致应用程序崩溃并显示一个“Acce…

免费SSL证书整理合集

有哪些免费的SSL证书呢&#xff1f;下面整理了一下非常有性价比的 一&#xff1a;免费单域名SSL证书&#xff1a;适用于只有一个域名的情况下使用 点击申请免费单域名SSL证书https://www.joyssl.com/certificate/select/joyssl-dv-single-free.html?nid7 二&#xff1a;通配…

基于单片机的篮球计分器设计

在当今的体育赛事中,比赛的计分系统对观众和运动员尤为重要,观众可以根据比分的实时显示为自己支持的队伍呐喊助威,运动员更是要靠着计分器来把握比赛的节奏,包括攻防转换、替补换人以及赛间休息等等。因此,为了让比赛进行得更加专业化和流畅化,我们有必要对比赛的计分系…