3.24作业

基于UDP的网络聊天室

项目需求:

  1. 如果有用户登录,其他用户可以收到这个人的登录信息
  2. 如果有人发送信息,其他用户可以收到这个人的群聊信息
  3. 如果有人下线,其他用户可以收到这个人的下线信息
  4. 服务器可以发送系统信息

服务器端代码

#include<myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.117.74"
#define PRINT_ERR(msg)                                      do                                                      {                                                       printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); perror(msg);                                        exit(-1);                                           } while (0)typedef struct
{char code; //操作码char name[32];char txt[128];
} msg_t;
//链表结构体
typedef struct _NODE
{struct sockaddr_in c_addr;struct _NODE *next;
} node_t;void creat_link(node_t **head);
int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead);
int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead);
int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead);int main(int argc, const char *argv[])
{//创建套接字int sockfd;if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){PRINT_ERR("socket error");}//创建服务器网络信息结构体struct sockaddr_in serviceaddr;memset(&serviceaddr, 0, sizeof(serviceaddr));serviceaddr.sin_family = AF_INET;serviceaddr.sin_addr.s_addr = inet_addr(argv[1]);serviceaddr.sin_port = htons(atoi(argv[2]));socklen_t serviceaddr_len = sizeof(serviceaddr);//将服务器网络信息结构体与套接字绑定if (bind(sockfd, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1){PRINT_ERR("bind error");}//创建客户端网络信息结构体struct sockaddr_in clientaddr;memset(&clientaddr, 0, sizeof(clientaddr));socklen_t clientaddr_len = sizeof(clientaddr);msg_t msg;//创建父子进程pid_t pid;pid = fork();if (pid == -1){PRINT_ERR("fork error");}else if (pid == 0){//子进程//接受数据并处理//定义链表头节点node_t *phead = NULL;creat_link(&phead);phead->next = NULL;while (1){memset(&msg, 0, sizeof(msg));memset(&clientaddr, 0, sizeof(clientaddr));if ((recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&clientaddr, &clientaddr_len)) == -1){PRINT_ERR("recvfrom error");}printf("%8s : [%s]\n", msg.name, msg.txt);switch (msg.code){case 'L':do_register(sockfd, msg, clientaddr, phead);break;case 'C':do_group_chat(sockfd, msg, clientaddr, phead);break;case 'Q':quit_group_chat(sockfd, msg, clientaddr, phead);break;}}}else if (pid > 0){//父进程//发系统消息msg.code='C';strcpy(msg.name,"server");while(1){fgets(msg.txt,128,stdin);msg.txt[strlen(msg.txt)-1]='\0';if(sendto(sockfd,&msg,sizeof(msg_t),0,(struct sockaddr *)&serviceaddr,serviceaddr_len)==-1){PRINT_ERR("sendto error");}}}close(sockfd);return 0;
}
//创建链表头节点函数
void creat_link(node_t **head)
{*head = (node_t *)malloc(sizeof(node_t));
}
//登录操作
int do_register(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{//遍历链表将登录信息发送给所以人node_t *p = phead;while (p->next != NULL){p = p->next;if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){PRINT_ERR("recvfrom error");}}//将登录的客户端信息插入保存在链表//头插//定义一个新的指针保存客户端信息node_t *newp = NULL;creat_link(&newp);newp->c_addr = clientaddr;newp->next = phead->next;phead->next = newp;return 0;
}int do_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{//遍历链表,将消息发给除自己之外的所有人node_t *p = phead;while (p->next != NULL){p = p->next;//判断链表客户端信息是否是自己//是自己就不发送if (memcmp(&(p->c_addr), &clientaddr, sizeof(clientaddr))){if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){PRINT_ERR("recvfrom error");}}}return 0;
}
//退出群聊操作
int quit_group_chat(int sockfd, msg_t msg, struct sockaddr_in clientaddr, node_t *phead)
{node_t *p = phead;while (p->next != NULL){//判断链表客户端信息是否是自己//是自己就不发送并且将自己的客户端信息在链表内删除if (memcmp(&(p->next->c_addr), &clientaddr, sizeof(clientaddr))){p = p->next;if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&(p->c_addr), sizeof(p->c_addr)) == -1){PRINT_ERR("recvfrom error");}}else{node_t *pnew;pnew = p->next;p->next = pnew->next;pnew->next = NULL;free(pnew);pnew = NULL;}}return 0;
}

客户端代码

#include<myhead.h>
#define SER_PORT 8888
#define SER_IP "192.168.117.74"
#define PRINT_ERR(msg)                                      do                                                      {                                                       printf("%s,%d,%s\n", __FILE__, __LINE__, __func__); perror(msg);                                        exit(-1);                                           } while (0)typedef struct
{char code; //操作码 char name[32];char txt[128];
} msg_t;int main(int argc, const char *argv[])
{//创建套接字int sockfd;if ((sockfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){PRINT_ERR("socket error");}//创建服务器网络信息结构体struct sockaddr_in serviceaddr;memset(&serviceaddr, 0, sizeof(serviceaddr));serviceaddr.sin_family = AF_INET;serviceaddr.sin_addr.s_addr = inet_addr(argv[1]);serviceaddr.sin_port = htons(atoi(argv[2]));socklen_t serviceaddr_len = sizeof(serviceaddr);//给服务器发送登录数据包msg_t msg;memset(&msg, 0, sizeof(msg_t));msg.code = 'L';printf("请输入用户名:");fgets(msg.name, 32, stdin);msg.name[strlen(msg.name) - 1] = '\0';strcpy(msg.txt, "加入群聊");if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1){PRINT_ERR("sendto error");}//创建父子进程pid_t pid;pid = fork();if (pid == -1){PRINT_ERR("fork error");}else if (pid == 0){//子进程//接受数据并处理while (1){//每次循环前将msg置零memset(&msg, 0, sizeof(msg));//接受服务器发过来的信息并打印到终端上if (recvfrom(sockfd, &msg, sizeof(msg_t), 0, NULL, NULL) == -1){PRINT_ERR("recvfrom error");}printf("%8s:[%s]\n", msg.name, msg.txt);}}else if (pid > 0){//父进程//发送消息while (1){   //memset会把name清除msg.code = 'C';fgets(msg.txt, 128, stdin);msg.txt[strlen(msg.txt) - 1] = '\0';if (strcmp(msg.txt, "quit") == 0){msg.code = 'Q';strcpy(msg.txt, "退出群聊");}if (sendto(sockfd, &msg, sizeof(msg_t), 0, (struct sockaddr *)&serviceaddr, serviceaddr_len) == -1){PRINT_ERR("sendto error");}if (strcmp(msg.txt, "退出群聊") == 0){break;}}kill(pid,SIGKILL);wait(NULL);close(sockfd);}return 0;
}

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

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

相关文章

matlab-双树复小波变换DTCWT(转自 MathWorks)

此示例展示了双树复小波变换 (DTCWT) 如何在信号、图像和体积处理方面提供优于临界采样 DWT 的优势。DTCWT 作为两个独立的双通道滤波器组来实现。为了获得本示例中描述的优点&#xff0c;您不能任意选择两个树中使用的缩放和小波滤波器。一棵树的低通&#xff08;缩放&#xf…

Github多账号共存

在开发阶段&#xff0c;如果同时拥有多个开源代码托管平台的账户&#xff0c;在代码的管理上非常麻烦。那么&#xff0c;如果同一台机器上需要配置多个账户&#xff0c;怎样才能确保不冲突&#xff0c;不同账户独立下载独立提交呢&#xff1f; 我们以两个github账号进行演示 …

docker desktop启动Kibana:No living connections, Error: No Living connections

Kibana启动之后一直报Kibana server is not ready yet 查看日志&#xff1a;No living connections, Error: No Living connections,连接ES失败&#xff01; 查看配置文件内容 /usr/share/kibana/config/kibana.yml 经过一系列查找资料和尝试之后&#xff0c;亲测以下方法可用…

阿里二面:谈谈ThreadLocal的内存泄漏问题?问麻了。。。。

引言 ThreadLocal在Java多线程编程中扮演着重要的角色&#xff0c;它提供了一种线程局部存储机制&#xff0c;允许每个线程拥有独立的变量副本&#xff0c;从而有效地避免了线程间的数据共享冲突。ThreadLocal的主要用途在于&#xff0c;当需要为每个线程维护一个独立的上下文…

字节算法岗二面,凉凉。。。

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

分治归并问题

“别让自我被拯救~” 谈谈归并与分治 当我们首次接触排序算法时&#xff0c;一定对所谓 "归并"方式排序的算法感到头疼~ 因为&#xff0c;我们难以形象出其不断 "分离"时&#xff0c;各个区域的状态。然而&#xff0c;即便 "归并"排序算法的学习…

新能源汽车充电桩消防安全视频智能可视化监管建设方案

一、方案背景 据应急管理部门统计公布的数据显示&#xff0c;仅2023年第一季度&#xff0c;新能源汽车自燃率就上涨了32%&#xff0c;平均每天就有8辆新能源汽车发生火灾&#xff08;含自燃&#xff09;。在已查明起火原因中&#xff0c;58%源于电池问题&#xff0c;19%源于碰…

输出当前时间

用途&#xff1a;在项目中一些属性中设置当前时间 实例代码 import java.time.LocalDateTime; import java.time.format.DateTimeFormatter;public class time {public static void main(String[] args){LocalDateTime china LocalDateTime.now(); DateTimeFormatter forma…

ASPICE学习笔记 ———— 过程模型(Process reference model)

文章目录 介绍过程模型Primary life cycle processes categoryAcquisition Process GroupSupply Process GroupSystem Engineering Processes GroupSoftware Engineering Processes Group Supporting life cycle processes categoryOrganizational life cycle processes catego…

【活动预告】本周四(3月28日)AI算法大模型备案线上活动

Al算法备案中心特邀十年合规专家「乐歌」&#xff0c;于本周四进行线上算法备案活动 支持AI创业者&#xff0c;免费咨询算法备案 3.28日20&#xff1a;00腾讯会议欢迎参与&#xff01; 扫码添加活动助理报名参加&#xff01;

四川宏博蓬达法律咨询有限公司:您身边的法律守护者

在快节奏的现代生活中&#xff0c;法律咨询服务已成为人们不可或缺的一部分。四川宏博蓬达法律咨询有限公司正是这样一个值得您信赖的法律服务伙伴。我们专注于为客户提供专业、高效、安全的法律服务&#xff0c;致力于成为您生活中的法律守护者。 一、专业团队&#xff0c;服务…

反沙箱思路总结

文章目录 反调试反沙箱时间对抗环境检测 反虚拟机黑DLL父进程检测傀儡进程后记 反调试 IsDebuggerPresent #include<windows.h> #include<stdio.h> BOOL check() {return IsDebuggerPresent(); } BOOL isPrime(long long number){if (number < 1)return FALSE…

制作一个RISC-V的操作系统七-UART初始化(UART NS16550A 规定 目标 发送数据 代码 extern)

文章目录 UARTNS16550A规定目标发送数据代码extern UART 对应到嵌入式开发中&#xff0c;qemu模拟的就是那块开发板&#xff08;硬件&#xff09; 电脑使用qemu时可以理解为qemu模拟了那块板子&#xff0c;同时那块板子与已经与你的电脑相连接了&#xff08;我们对应的指定的内…

水牛社五大赚钱栏目概览:轻松了解项目核心与赚钱原理

很多新用户首次访问水牛社官网时&#xff0c;可能会感到有些迷茫。由于软件介绍相对较长&#xff0c;部分朋友可能缺乏耐心细读。然而&#xff0c;若您真心希望在网络上找到赚钱的机会&#xff0c;深入了解我们的发展历程将大有裨益。简而言之&#xff0c;本文旨在快速带您领略…

基于tcp协议的网络通信(将服务端守护进程化)

目录 守护进程化 引入 介绍 如何实现 思路 接口 -- setsid 注意点 实现代码 daemon.hpp log.hpp 运行情况 前情提要 -- 前后台任务介绍(区别命令),sessionsid介绍,session退出后的情况(nuhup,终端进程控制组),任务进程组概念,任务与进程组的关系,-bash介绍-CSDN博客…

ros找不到生成的可执行文件[rosrun] Couldn‘t find executable named hello_world_cpp below

catkin_make之后source ./devel/setup.bash source之后运行节点的时候,ros找不到可执行文件&#xff08;其实tab键补不齐就没找到了&#xff09; 手动查找发现生成的可执行文件在build下不在devel/lib下&#xff0c;所以白source&#xff0c;压根找不到。 查找原因说是因为CMa…

java项目将静态资源中的文件转为浏览器可访问的http地址

新增一个类叫啥无所谓&#xff0c;主要是实现 WebMvcConfigurer 加上注解 Configuration项目启动时加入bean中 只操作addResourceHandlers这一个方法 其他都没用 文章下方附带一个简易的上传图片代码 package cn.exam.config;import org.springframework.context.annotati…

Personal Website

Personal Website Static Site Generators hexo hugo jekyll Documentation Site Generator gitbook vuepress vitepress docsify docute docusaurus Deployment 1. GitHub Pages 2. GitLab Pages 3. vercel 4. netlify Domain 域名注册 freessl 域名解析域名…

DMA控制器

前言 大家好&#xff0c;我是jiantaoyab&#xff0c;这是我作为学习笔记的25篇&#xff0c;本篇文章给大家介绍DMA。 无论 I/O 速度如何提升&#xff0c;比起 CPU&#xff0c;总还是太慢。如果我们对于 I/O 的操作&#xff0c;都是由 CPU 发出对应的指令&#xff0c;然后等待…

【数据结构】线性表的定义与基本操作

&#x1f388;个人主页&#xff1a;豌豆射手^ &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 &#x1f917;收录专栏&#xff1a;数据结构 &#x1f91d;希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出指正&#xff0c;让我们共同学习、交流进…