网络聊天室
一、项目要求
利用UDP协议,实现一套聊天室软件。服务器端记录客户端的地址,客户端发送消息后,服务器群发给各个客户端软件。
问题思考
- 客户端会不会知道其它客户端地址?
UDP客户端不会直接互连,所以不会获知其它客户端地址,所有客户端地址存储在服务器端。
- 有几种消息类型?
- 登录:服务器存储新的客户端的地址。把某个客户端登录的消息发给其它客户端。
- 聊天:服务器只需要把某个客户端的聊天消息转发给所有其它客户端。
- 退出:服务器删除退出客户端的地址,并把退出消息发送给其它客户端。
- 服务器如何存储客户端的地址?
数据结构可以选择线性数据结构
链表节点结构体:
struct node{
struct sockaddr_in addr;//data memcmp
struct node *next;
};
消息对应的结构体(同一个协议)
typedef struct msg_t
{
int type;//'L' C Q enum un{login,chat,quit};
char name[32];//用户名
char text[128];//消息正文
}MSG_t;
int memcmp(void *s1,void *s2,int size)
- 客户端如何同时处理发送和接收?
客户端不仅需要读取服务器消息,而且需要发送消息。读取需要调用recvfrom,发送需要先调用gets,两个都是阻塞函数。所以必须使用多任务来同时处理,可以使用多进程或者多线程来处理。
二、程序流程图
服务器端
客户端

三、代码实现
server.c代码部分:
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<string.h>
#include<stdlib.h>
#include <sys/wait.h>
#include<dirent.h>
#include<sys/stat.h>
#include<signal.h>
#include <pthread.h>struct sockaddr_in serveraddr,caddr;
enum type_t//枚举
{Login,Chat,Quit,
};
typedef struct MSG
{char type;//L C Qchar 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;
}
client.c代码部分:
#include<stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<string.h>
#include<stdlib.h>
#include <sys/wait.h>
#include<dirent.h>
#include<sys/stat.h>enum type_t
{Login,Chat,Quit,
};
typedef struct
{char type;//L C Qchar 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;
}
相关文章:
网络聊天室
一、项目要求 利用UDP协议,实现一套聊天室软件。服务器端记录客户端的地址,客户端发送消息后,服务器群发给各个客户端软件。 问题思考 客户端会不会知道其它客户端地址? UDP客户端不会直接互连,所以不会获知其它客…...
ChatGPT只是玩具:生成式人工智能在不同行业的应用
源自:IT经理网 生成式人工智能的十一个行业用例 打开生成式 AI的正确姿势 声明:公众号转载的文章及图片出于非商业性的教育和科研目的供大家参考和探讨,并不意味着支持其观点或证实其内容的真实性。版权归原作者所有,如转载稿涉及版权等问题&…...
RestFul的风格是什么
RestFul的风格是什么? 当我们谈论RESTful风格时,它指的是一种设计和构建网络应用程序的原则和约定。以下是RESTful风格的一些主要特点: 资源:将应用程序的功能封装为资源,每个资源都有一个唯一的标识符(U…...
【自制C/C++小项目JuLongEditor】使用Windows控制台API来制作一个简单的文本编辑器
2023年8月22日,周二下午 昨天花了一个下午和晚上来制作的, 实现了一些基本的功能, 但由于代码只有130行,所以存在很多不足之处 GitHub:GitHub - JuLongZhiLu/JuLongEditor: C/C小项目,使用Windows控制台…...
中国芯,寻找新赛道迫在眉睫
北京华兴万邦管理咨询有限公司 商瑞 陈皓 近期国内半导体行业的热点可以用两个“有点多”来描述,一个是中国芯群体中上市公司股价闪崩的有点多,另一个是行业和企业的活动有点多。前者说明了许多国内芯片设计企业(fabless商业模式)…...
C++ 好用的格式化库--fmt
背景 fmt 库是一个开源的 C 格式化库,它提供了一种简洁、安全和高效的方式来进行字符串格式化。该库的设计目标是提供与 Python 的字符串格式化语法类似的功能,同时保持 C 的类型安全性和性能。 下载与安装 官网下载 fmt 官网地址:https:…...
微信小程序教学系列(3)
微信小程序教学系列 第三章:小程序高级开发技巧 1. 小程序API的使用 小程序API简介 小程序API是小程序提供的一系列接口,用于实现各种功能和操作。通过调用小程序API,可以实现页面跳转、数据存储、网络请求等功能。 使用小程序API的步骤…...
ORB-SLAM系列算法演进
ORB-SLAM算法是特征点法的代表,当前最新发展的ORB-SLAM3已经将相机模型抽象化,适用范围非常广,虽然ORB-SLAM在算法上的创新并不是很丰富,但是它在工程上的创新确实让人耳目一新,也能更好的为AR、机器人的算法实现落地。…...
solidity0.8.0的应用案例11:透明代理合约
选择器冲突 智能合约中,函数选择器(selector)是函数签名的哈希的前4个字节。例如mint(address account)的选择器为bytes4(keccak256("mint(address)")),也就是0x6a627842. 由于函数选择器仅有4个字节,范围很小,因此两个不同的函数可能会有相同的选择器,例如…...
最新消息:谷歌将在Chromebook上运用UWB技术,无线通信更上一层
超宽带(UWB)技术是一种创新的短距离无线通信技术,具有高速数据传输和精确定位物体位置的优势。尽管该技术已经存在一段时间,但最近开始广泛应用于各种设备中。据最新报道,Pixel Watch 2可能会搭载UWB模块,这…...
php+echarts实现数据可视化实例3
效果 全部代码 <?php include(includes/session.inc); include(includes/SQL_CommonFunctions.inc); ?> <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" …...
ubuntu下安装Sphinx,编译pdf
安装WSL2: 以管理员身份打开PowerShellwsl --install 来安装其他 Linux 发行版wsl --list --verbose 查看安装在 Windows 计算机上的 Linux 发行版列表 安装sphinx: sudo apt-get updatesudo apt-get install python3-sphinxsudo apt-get install lat…...
vue2.x项目从0到1(七)之用户权限
此章节偏理论知识 对于小一点的项目 比如说角色都是平级的 那我们直接像之前 vue2.x项目从0到1(二)之后台管理侧边栏(动态渲染路由以及高亮)_vue动态渲染侧边栏_关忆北_的博客-CSDN博客这样渲染就行了 但是一旦项目大了 …...
上传镜像到阿里云的ACR
1、开通阿里云ACR 2、在ACR 中创建命名空间 3、本地安装docker 4、登录到 开通ACR,需要配置访问凭证 [rootmaster ~]# docker login --username***lb registry.cn-beijing.aliyuncs.com Password: 5、给镜像打标签 [rootmaster ~]# docker images REPOSITORY …...
ahooks.js:一款强大的React Hooks库及其API使用教程(五)
一、ahooks.js简介二、ahooks.js安装三、继续ahooks.js API的介绍与使用教程61. useEventTarget62. useExternal63. useFavicon64. useMutationObserver65. useLongPress66. useScroll67. useResponsive68. useFocusWithin69. useControllableValue70. useEventEmitter 一、aho…...
MySQL TCL 事务控制
文章目录 1.事务四大特性2.事务并发问题3.事务隔离级别4.隔离级别查看与设置5.动提交事务5.1 查看自动提交事务5.2 关闭或开启自动提交事务 6.事务执行的基本流程7.设置事务的保存点参考文献 说到事务控制,先说一下数据库的事务是什么以及 MySQL 中我们必知的知识点…...
【Ubuntu】从Graylog到Grafana Loki:构建更强大的网络设备管理和监控系统
在将Graylog部署到生产环境时,我们遇到了一些问题,其中最主要的是无法安装MongoDB并且无法随时重启机器去修改BIOS设置来修复问题 【WARNING: MongoDB 5.0 requires a CPU with AVX support, and your current system does not appear to have that! 】。…...
[JavaWeb]【八】web后端开发-Mybatis
目录 一 介绍 二 Mybatis的入门 2.1 快速入门 2.1.1 准备SpringBoot工程 2.1.2 创建数据库mybatis以及对应库表user 2.1.3 创建User实体类 2.1.4 配置application.properties数据库连接信息 2.1.5 编写sql语句(注解方式) 2.1.6 测试运行 2.1.7 配…...
Flink源码之Checkpoint执行流程
Checkpoint完整流程如上图所示: JobMaster的CheckpointCoordinator向所有SourceTask发送RPC触发一次CheckPointSourceTask向下游广播CheckpointBarrierSouceTask完成状态快照后向JobMaster发送快照结果非SouceTask在Barrier对齐后完成状态快照向JobMaster发送快照结…...
【工具使用】Git的使用
dev代表开发版 1. git clone 命令 通过 git add <name> 对文件进行跟踪,把<name>加入到暂存区 git commit -m XXXXXXX 提交修改并补充XXXXX作为注释 “暂存”状态:出现了一些修改,但是还没有提交 对于Java来说,.cl…...
【Oracle APEX开发小技巧12】
有如下需求: 有一个问题反馈页面,要实现在apex页面展示能直观看到反馈时间超过7天未处理的数据,方便管理员及时处理反馈。 我的方法:直接将逻辑写在SQL中,这样可以直接在页面展示 完整代码: SELECTSF.FE…...
3.3.1_1 检错编码(奇偶校验码)
从这节课开始,我们会探讨数据链路层的差错控制功能,差错控制功能的主要目标是要发现并且解决一个帧内部的位错误,我们需要使用特殊的编码技术去发现帧内部的位错误,当我们发现位错误之后,通常来说有两种解决方案。第一…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
Vue2 第一节_Vue2上手_插值表达式{{}}_访问数据和修改数据_Vue开发者工具
文章目录 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染2. 插值表达式{{}}3. 访问数据和修改数据4. vue响应式5. Vue开发者工具--方便调试 1.Vue2上手-如何创建一个Vue实例,进行初始化渲染 准备容器引包创建Vue实例 new Vue()指定配置项 ->渲染数据 准备一个容器,例如: …...
Reasoning over Uncertain Text by Generative Large Language Models
https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829https://ojs.aaai.org/index.php/AAAI/article/view/34674/36829 1. 概述 文本中的不确定性在许多语境中传达,从日常对话到特定领域的文档(例如医学文档)(Heritage 2013;Landmark、Gulbrandsen 和 Svenevei…...
LeetCode - 199. 二叉树的右视图
题目 199. 二叉树的右视图 - 力扣(LeetCode) 思路 右视图是指从树的右侧看,对于每一层,只能看到该层最右边的节点。实现思路是: 使用深度优先搜索(DFS)按照"根-右-左"的顺序遍历树记录每个节点的深度对于…...
【网络安全】开源系统getshell漏洞挖掘
审计过程: 在入口文件admin/index.php中: 用户可以通过m,c,a等参数控制加载的文件和方法,在app/system/entrance.php中存在重点代码: 当M_TYPE system并且M_MODULE include时,会设置常量PATH_OWN_FILE为PATH_APP.M_T…...
VisualXML全新升级 | 新增数据库编辑功能
VisualXML是一个功能强大的网络总线设计工具,专注于简化汽车电子系统中复杂的网络数据设计操作。它支持多种主流总线网络格式的数据编辑(如DBC、LDF、ARXML、HEX等),并能够基于Excel表格的方式生成和转换多种数据库文件。由此&…...
Java详解LeetCode 热题 100(26):LeetCode 142. 环形链表 II(Linked List Cycle II)详解
文章目录 1. 题目描述1.1 链表节点定义 2. 理解题目2.1 问题可视化2.2 核心挑战 3. 解法一:HashSet 标记访问法3.1 算法思路3.2 Java代码实现3.3 详细执行过程演示3.4 执行结果示例3.5 复杂度分析3.6 优缺点分析 4. 解法二:Floyd 快慢指针法(…...
电脑桌面太单调,用Python写一个桌面小宠物应用。
下面是一个使用Python创建的简单桌面小宠物应用。这个小宠物会在桌面上游荡,可以响应鼠标点击,并且有简单的动画效果。 import tkinter as tk import random import time from PIL import Image, ImageTk import os import sysclass DesktopPet:def __i…...
