UDP聊天室项目

代码思路

服务器

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>//链表节点结构体:
typedef struct node
{struct sockaddr_in addr; //data   memcmpstruct node *next;
} link_t;//类型
enum type_t
{login,chat,quit,
};//消息对应的结构体(同一个协议)
typedef struct msg_t
{int type;       //'L' C  Q    enum un{login,chat,quit};char name[32];  //用户名char text[128]; //消息正文
} MSG_t;link_t *link_creat();
void client_login(int sockfd, link_t *p, MSG_t msg, struct sockaddr_in caddr);
void client_quit(int sockfd, link_t *p, MSG_t msg, struct sockaddr_in caddr);
void client_chat(int sockfd, link_t *p, MSG_t msg, struct sockaddr_in caddr);int main(int argc, char const *argv[])
{// 创建套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket err");return -1;}printf("sockfd:%d\n", sockfd);// 绑定struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[1]));saddr.sin_addr.s_addr = INADDR_ANY;socklen_t len = sizeof(caddr);if (bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0){perror("bind err");return -1;}printf("bind ok\n");// 创建链表link_t *p = link_creat();printf("creat ok\n");MSG_t msg;// 可扩展功能,服务器可以给所有用户发送“公告”pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0){while (1){fgets(msg.text, sizeof(msg.text), stdin);if (msg.text[strlen(msg.text) - 1] == '\n')msg.text[strlen(msg.text) - 1] = '\0';msg.type = chat;strcpy(msg.name, "server");sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&saddr, sizeof(saddr));}}else{while (1){if (recvfrom(sockfd, &msg, sizeof(msg), 0, (struct sockaddr *)&caddr, &len) < 0){perror("recvfrom err");return -1;}printf("type:%d\n", msg.type);switch (msg.type){case login: // 上线函数client_login(sockfd, p, msg, caddr);break;case chat: // 聊天函数client_chat(sockfd, p, msg, caddr);break;case quit: // 下线函数client_quit(sockfd, p, msg, caddr);break;default:break;}}}close(sockfd);return 0;
}
// 创建链表
link_t *link_creat()
{// 给头结点开辟空间link_t *p = (link_t *)malloc(sizeof(link_t));if (p == NULL){perror("malloc err");return NULL;}// 初始化头结点p->next = NULL;return p;
}// 客户端上线功能:将用户上线消息发送给其他用户,并将用户信息添加到链表中
void client_login(int sockfd, link_t *p, MSG_t msg, struct sockaddr_in caddr)
{printf("%s  login....\n", msg.name);// 先遍历链表// 再插入新的节点while (p->next != NULL){p = p->next;sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));}link_t *pnew = (link_t *)malloc(sizeof(link_t));pnew->addr = caddr;pnew->next = NULL;p->next = pnew;return;
}
// 聊天功能:转发消息到在链表中除了自己的所有用户
void client_chat(int sockfd, link_t *p, MSG_t msg, struct sockaddr_in caddr)
{printf("%s says %s\n", msg.name, msg.text);while (p->next != NULL){p = p->next;// strcmp:对比前后两个字符串中的内容是否一致// memcmp:对比前后两个对应的地址(任意类型)的内容是否一致if (memcmp(&(p->addr), &caddr, sizeof(caddr))){sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));}}return;
}
// 客户端退出功能:将用户下线消息发送给其他用户,将下线用户从链表中删除
void client_quit(int sockfd, link_t *p, MSG_t msg, struct sockaddr_in caddr)
{printf("%s quit.......\n", msg.name);link_t *pdel = NULL;while (p->next != NULL){if (memcmp(&(p->next->addr), &caddr, sizeof(caddr))){// 不是自己p = p->next;sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&(p->addr), sizeof(p->addr));}else{// 是自己,删除节点pdel = p->next;p->next = pdel->next;free(pdel);pdel = NULL;}}return;
}

客户端

#include <stdio.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>//链表节点结构体:
typedef struct node
{struct sockaddr_in addr; //data   memcmpstruct node *next;
} link_t;//类型
enum type_t
{login,chat,quit,
};//消息对应的结构体(同一个协议)
typedef struct msg_t
{int type;       //'L' C  Q    enum un{login,chat,quit};char name[32];  //用户名char text[128]; //消息正文
} MSG_t;int main(int argc, char const *argv[])
{int ret;// 创建套接字int sockfd = socket(AF_INET, SOCK_DGRAM, 0);if (sockfd < 0){perror("socket err");return -1;}printf("sockfd:%d\n", sockfd);// 绑定struct sockaddr_in saddr, caddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(atoi(argv[2]));saddr.sin_addr.s_addr = inet_addr(argv[1]);socklen_t len = sizeof(caddr);MSG_t msg;// 给服务器发送上线消息printf("请输入用户名:");fgets(msg.name, sizeof(msg.name), stdin);if (msg.name[strlen(msg.name) - 1] == '\n')msg.name[strlen(msg.name) - 1] = '\0';msg.type = login;sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&saddr, sizeof(saddr));pid_t pid = fork();if (pid < 0){perror("fork err");return -1;}else if (pid == 0) // 循环接受服务器消息{while (1){ret = recvfrom(sockfd, &msg, sizeof(MSG_t), 0, NULL, NULL);if (ret < 0){perror("recv from err");return -1;}if (msg.type == login)printf("%s login.......\n", msg.name);else if (msg.type == chat)printf("%s says %s\n", msg.name, msg.text);else if (msg.type == quit)printf("%s quit.......\n", msg.name);}}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")){msg.type = quit;sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&saddr, sizeof(saddr));break;}else{msg.type = chat;sendto(sockfd, &msg, sizeof(MSG_t), 0, (struct sockaddr *)&saddr, sizeof(saddr));}}kill(pid, SIGINT);wait(NULL);}close(sockfd);return 0;
}

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

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

相关文章

JVM 调优篇7 调优案例1-堆空间的优化解决

一 jvm优化 1.1 优化实施步骤* 1)减少使用全局变量和大对象&#xff1b; 2)调整新生代的大小到最合适&#xff1b; 3)设置老年代的大小为最合适&#xff1b; 4)选择合适的GC收集器&#xff1b; 1.2 关于GC优化原则 多数的Java应用不需要在服务器上进行GC优化&#xff1…

ESP8266做httpServer提示Header fields are too long for server to interpret

CONFIG_HTTP_BUF_SIZE512 CONFIG_HTTPD_MAX_REQ_HDR_LEN1024 CONFIG_HTTPD_MAX_URI_LEN512CONFIG_HTTPD_MAX_REQ_HDR_LEN由512改为1024

02 基于STM32的按键控制继电器驱动电机

本专栏所有源资料都免费获取&#xff0c;没有任何隐形消费。 注意事项&#xff1a;STM32仿真会存在各种各样BUG&#xff0c;且尽量按照同样仿真版本使用。本专栏所有的仿真都采用PROTEUS8.15。 本文已经配置好STM32F103C8T6系列&#xff0c;在PROTUES仿真里&#xff0c;32单片…

Games101图形学笔记——着色

Shading Z-buffering&#xff08;深度缓冲&#xff09; Shading&#xff08;着色&#xff09;画家算法Z-BufferShading(着色&#xff09;Blinn-Phong Reflectance Model&#xff08;布林冯反射模型&#xff09;漫反射能量守恒 着色高光Blinn-Phong Reflection ModelShadingFreq…

webGL 综合教程100+【目录】

webGL 综合教程100旨在为开发者提供两大方面的知识信息&#xff1a;&#xff08;1&#xff09;提供详细的每个api知识点的详解 &#xff08;2&#xff09;提供实战的示例&#xff0c;提供源代码。 在这量大系统性的知识下&#xff0c;给用户提供清晰的思路和示例参考&#xff0…

IEEE-754 32位十六进制数 转换为十进制浮点数

要将 IEEE-754 32位十六进制数 转换为 十进制浮点数&#xff0c;可以使用LabVIEW中的 Type Cast 函数。以下是一些具体步骤&#xff0c;以及相关实例的整理&#xff1a; 实现步骤&#xff1a; 输入十六进制数&#xff1a;在LabVIEW中&#xff0c;首先需要创建一个输入控制器&am…

传输层协议——udp/tcp

目录 再谈端口号 udp 协议 理解报头 udp特点 缓冲区 udp使用的注意事项 tcp协议 TCP的可靠性与提高效率的策略 序号/确认序号 窗口大小 ACK&#xff1a; PSH URG RST 保活机制 重传 三次握手(SYN) 四次挥手(FIN) 流量控制 滑动窗口 拥塞控制 延迟应答 捎带应答 面…

GPT撰写开题报告教程——课题确定及文献调研

撰写开题报告是一项复杂而重要的任务&#xff0c;需要涵盖从主题选择到文献综述、研究方法等多个环节。借助AI&#xff0c;如ChatGPT&#xff0c;可以显著提高这一过程的效率以及内容的质量。本文将详细探讨如何一步步利用ChatGPT撰写开题报告。 一、开题报告内容 一个清晰的…

[数据集][目标检测]智慧养殖场肉鸡健康状态检测数据集VOC+YOLO格式4657张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;4657 标注数量(xml文件个数)&#xff1a;4657 标注数量(txt文件个数)&#xff1a;4657 标注…

基于SpringBoot的社区宠物管理与推荐系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 1.课题的基本内容&#xff0c;可能遇到的困难&#xff0c;提出解决问题的方法和措施 2.1课题的基本内容 本课题主要研究基于SpringBoot的社区宠物管理与推荐系统的设计与实现。用户注册登录系统前端后可以可以实现对宠物信息的…

保护您的隐私:隐藏 IP 地址的重要性

在当今的数字时代&#xff0c;我们的在线隐私和安全变得比以往任何时候都更加重要。浏览互联网时保护自己的一种方法是隐藏您的 IP 地址。 但是为什么要隐藏您的 IP 地址以及如何有效地做到这一点&#xff1f; 隐藏您的 IP 地址有助于保护您的在线匿名性。您的 IP 地址就像您的…

vscode技巧-eslint配置

开发环境 jsvue3axios 下载插件 Eslint、Prettfier 配置过程 1.配置eslint 进入settings&#xff0c;输入eslint&#xff0c;在settings.json中替换一下文件 // #每次保存的时候自动格式化 {"editor.codeActionsOnSave": {"source.fixAll.eslint": &…

低代码开发平台系统架构概述

概述 织信低代码开发平台&#xff08;产品全称&#xff1a;织信Informat&#xff09;是一款集成了应用设计、运行与管理的综合性平台。它提供了丰富的功能模块&#xff0c;帮助用户快速构建、部署和维护应用程序。织信低代码平台通过集成丰富的功能模块&#xff0c;为用户提供…

国产分布式数据库-tidb单机部署文档

tidb单机部署文档 1、创建用户 #创建用户 useradd tidb #设置密码 passwd tidb2、配置免密码登录 编辑/etc/sudoers文件,文末加入&#xff1a; tidb ALL(ALL) NOPASSWD:ALL如果想要控制某个用户(或某个组用户)只能执行root权限中的一部分命令, 或者允许某些用户使用sudo时…

游戏各个知识小点汇总

抗锯齿原理记录 SSAA&#xff1a;把成像的图片放大N倍&#xff0c;然后每N个点进行平均值计算。一般N为2的倍数。比如原始尺寸是1000x1000&#xff0c;长宽各放大2倍变成2000x2000。 举例&#xff1a; 原始尺寸&#xff1a; 放大2倍后 最后平均值计算成像&#xff1a; MSAA&…

[OpenCV] 数字图像处理 C++ 学习——14霍夫变换直线、圆检测 附完整代码

文章目录 前言1.霍夫变换原理(1)霍夫变换检测直线的原理(2)霍夫变换检测圆的原理 2.代码实现(1)霍夫直线检测(2)霍夫圆检测 3.完整代码 前言 霍夫变换是一种有效的检测图像中的几何形状&#xff08;如直线、圆等&#xff09;的算法。霍夫变换通过将几何形状的检测问题转化为参…

python学习第十节:爬虫基于requests库的方法

python学习第十节&#xff1a;爬虫基于requests库的方法 requests模块的作用&#xff1a; 发送http请求&#xff0c;获取响应数据&#xff0c;requests 库是一个原生的 HTTP 库&#xff0c;比 urllib 库更为容易使用。requests 库发送原生的 HTTP 1.1 请求&#xff0c;无需手动…

引领智能家居新风尚,WTN6040F门铃解决方案——让家的呼唤更动听

在追求高效与便捷的智能家居时代&#xff0c;每一个细节都承载着我们对美好生活的向往。WTN6040F&#xff0c;作为一款专为现代家庭设计的低成本、高性能门铃解决方案&#xff0c;正以其独特的魅力&#xff0c;悄然改变着我们的居家生活体验。 芯片功能特点&#xff1a; 1.2.4…

关于订单信息的Excel数据分析报告

提升自己&#xff0c;掌握数据分析的能力&#xff0c;最快的方式就是实践&#xff01; 这里又是一个Excel数据分析项目的分析报告&#xff0c;有需要项目配套数据集的可以关注私信我免费获取(●◡●)

Skytower

一、安装配置靶机 下载地址: SkyTower: 1 ~ VulnHub 下载之后解压发现是VirtualBox格式的 我们下载一个VirtualBox&#xff0c;这是官网 Downloads – Oracle VirtualBox 安装到默认路径就 打开后点击注册 选择解压后的vbox文件 然后点击左上角管理 点击导出虚拟电脑&…