3.22网络编程小项目
基于UDP的网络聊天室
项目需求:
- 如果有用户登录,其他用户可以收到这个人的登录信息
- 如果有人发送信息,其他用户可以收到这个人的群聊信息
- 如果有人下线,其他用户可以收到这个人的下线信息
- 服务器可以发送系统信息

服务器
#include <myhead.h>
// #define SER_IP "192.168.141.134"
// #define SER_PORT 8888
typedef struct Node // 链表存储客户端的所有信息
{struct sockaddr_in cin; // 存储客户端的网络地址信息struct Node *next;
} *List;
typedef struct Message // 消息结构体
{char type;char name[20];char text[128];
} msg_t;
struct sockaddr_in cin; // 客户端地址信息结构体// 单链表节点创建函数
List create_node()
{List p = (List)malloc(sizeof(struct Node));if (NULL == p)return NULL;p->next = NULL;return p;
}
// 客户端链表尾插
List insert_rear(List head, struct sockaddr_in cin)
{List s = create_node();if (NULL == s)return head;s->cin = cin;if (NULL == head){head = s;return s;}else{List p = head;while (p->next != NULL)p = p->next;p->next = s;return head;}
}
// 客户端接入服务器通知函数
void chat_all_join(List head, msg_t msg, int sfd)
{List p = head;char buf[50] = "";while (p->next != NULL){snprintf(buf, sizeof(buf), "[%s:%d]%s加入聊天室\n", inet_ntoa(p->cin.sin_addr), ntohs(p->cin.sin_port), msg.name);sendto(sfd, buf, sizeof(buf), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));p = p->next;}
}
// 客户端消息转发函数
void chat_all(List head, struct Message msg, int sfd, struct sockaddr_in cin)
{List p = head;char rbuf[200] = "";while (p->next != NULL){snprintf(rbuf, sizeof(rbuf), "[%s:%d]%s:%s\n", inet_ntoa(p->cin.sin_addr), ntohs(p->cin.sin_port), msg.name, msg.text);sendto(sfd, rbuf, sizeof(rbuf), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));p = p->next;}snprintf(rbuf, sizeof(rbuf), "[%s:%d]%s:%s\n", inet_ntoa(p->cin.sin_addr), ntohs(p->cin.sin_port), msg.name, msg.text);sendto(sfd, rbuf, sizeof(rbuf), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
// 客户端发送退出消息函数
void chat_all_quit(List head, struct Message msg, int sfd)
{char wbuf[200] = "";List p = head;while (p->next != NULL){snprintf(wbuf, sizeof(wbuf), "[%s:%d]%s:退出了聊天室\n", inet_ntoa(p->cin.sin_addr), ntohs(p->cin.sin_port), msg.name);sendto(sfd, wbuf, sizeof(wbuf), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));p = p->next;}snprintf(wbuf, sizeof(wbuf), "[%s:%d]%s:退出了聊天室\n", inet_ntoa(p->cin.sin_addr), ntohs(p->cin.sin_port), msg.name);sendto(sfd, wbuf, sizeof(wbuf), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));
}
// 链表中删除该地址信息
List exit_chat(List head)
{if (head->next == NULL) // 只有一个客户端时{free(head);head = NULL;return head;}List p = head;while (p->next != NULL) // 两个以上客户端{if (memcmp(&(p->next->cin), &cin, sizeof(cin)) == 0) // 找到p下一个节点地址信息符合的{List del = p->next;p->next = del->next;free(del);del = NULL;break;}else{p = p->next;}}return head;
}
int main(int argc, const char *argv[])
{// 创建通信的套接字文件描述符int sfd = -1;if ((sfd = socket(AF_INET, SOCK_DGRAM, 0)) == -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;}if (argc < 3){fprintf(stderr, "请输入ip和端口号\n");return -1;}// 给当前套接字绑定结构体信息struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(atoi(argv[2]));sin.sin_addr.s_addr = inet_addr(argv[1]);if (bind(sfd, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("bind error");return -1;}// 准备文件描述符容器fd_set readfds, tempfds;FD_ZERO(&readfds);FD_SET(0, &readfds);FD_SET(sfd, &readfds);int maxfd = sfd;// 定义变量存放客户端地址信息结构体,及客户端消息struct sockaddr_in cin;socklen_t socklen = sizeof(cin);struct Message msg;List head = NULL;char buf[128] = "";while (1){tempfds = readfds;if (select(maxfd + 1, &tempfds, NULL, NULL, NULL) == -1){perror("select error");return -1;}// 收到消息if (FD_ISSET(sfd, &tempfds)){recvfrom(sfd, &msg, sizeof(msg), 0, (struct sockaddr *)&cin, &socklen);switch (msg.type){case 'L': // 客户端加入{head = insert_rear(head, cin); // 尾插入链表chat_all_join(head, msg, sfd);printf("[%s:%d]%s加入聊天室\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);};break;case 'C': // 客户端消息{chat_all(head, msg, sfd, cin);printf("[%s:%d]%s:%s\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name, msg.text);};break;case 'Q': // 客户端退出{chat_all_quit(head, msg, sfd);printf("[%s:%d]%s退出聊天室\n", inet_ntoa(cin.sin_addr), ntohs(cin.sin_port), msg.name);head = exit_chat(head);};break;default:printf("type error\ttype=%c\n", msg.type);return -1;}}// 发送消息if (FD_ISSET(0, &tempfds)){memset(buf, 0, sizeof(buf));fgets(buf, sizeof(buf), stdin);buf[strlen(buf) - 1] = '\0';char wbuf[56] = "";snprintf(wbuf, sizeof(wbuf), "***system***%s\n", buf);List p = head;while (p != NULL){sendto(sfd, wbuf, sizeof(wbuf), 0, (struct sockaddr *)&(p->cin), sizeof(p->cin));p = p->next;}}}return 0;
}
客户端
#include <myhead.h>
// #define SER_IP "192.168.141.128"
// #define SER_PORT 8888
struct Message
{char type;char name[20];char text[128];
};
int main(int argc, const char *argv[])
{struct Message msg;// 创建通信用套接字文件描述符int cfd = -1;if ((cfd = socket(AF_INET, SOCK_DGRAM, 0)) == -1){perror("socket error");return -1;}if (argc < 3){fprintf(stderr, "请输入ip和端口号\n");return -1;}// 填写服务器的地址信息结构体struct sockaddr_in sin;sin.sin_family = AF_INET;sin.sin_port = htons(atoi(argv[2]));sin.sin_addr.s_addr = inet_addr(argv[1]);char name[20] = "";// 发送客户端的登录信息printf("请输入昵称:");fgets(name, sizeof(name), stdin);name[strlen(name) - 1] = '\0';strcpy(msg.name, name);msg.type = 'L';if (sendto(cfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, sizeof(sin)) == -1){perror("sendto error");return -1;}else{printf("加入聊天服务器成功\n");}// 准备文件描述符容器fd_set readfds, tempfds;FD_ZERO(&readfds);FD_SET(0, &readfds);FD_SET(cfd, &readfds);int maxfd = cfd;while (1){tempfds = readfds;int res = select(maxfd + 1, &tempfds, NULL, NULL, NULL);if (res == -1){perror("select error");return -1;}// 发数据if (FD_ISSET(0, &tempfds)){memset(msg.text, 0, sizeof(msg.text));read(0, msg.text, sizeof(msg.text));msg.text[strlen(msg.text) - 1] = '\0';// 客户端退出if (strcmp(msg.text, "quit") == 0){msg.type = 'Q';sendto(cfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, sizeof(sin));printf("本机已下线\n");close(cfd);return 0;}// 与其他客户端通信else{msg.type = 'C';sendto(cfd, &msg, sizeof(msg), 0, (struct sockaddr *)&sin, sizeof(sin));}}// 收数据if (FD_ISSET(cfd, &tempfds)){char buf[128] = "";// 不接收服务器的地址信息结构体recvfrom(cfd, buf, sizeof(buf), 0, NULL, NULL);printf("%s", buf);fflush(stdout);}}return 0;
}相关文章:
3.22网络编程小项目
基于UDP的网络聊天室 项目需求: 如果有用户登录,其他用户可以收到这个人的登录信息如果有人发送信息,其他用户可以收到这个人的群聊信息如果有人下线,其他用户可以收到这个人的下线信息服务器可以发送系统信息 服务器 #includ…...
Git原理及使用
1、Git初识 Git是一种版本控制器: 对于同一份文件,做多次改动,Git会记录每一次改动前后的文件。 通俗的讲就是⼀个可以记录⼯程的每⼀次改动和版本迭代的⼀个管理系统,同时也⽅便多⼈协同作业。 注意: Git其实只能跟踪⽂本⽂件的改动,⽐如TXT⽂件,⽹⻚,所有的程序代码…...
Milvus 向量数据库介绍及使用
一、Milvus 介绍及安装 Milvus 于 2019 年创建,其目标只有一个:存储、索引和管理由深度神经网络和其他机器学习 (ML) 模型生成的大量嵌入向量。它具备高可用、高性能、易拓展的特点,用于海量向量数据的实时召回。 作为专门为处理输入向量查…...
STP环路避免实验(华为)
思科设备参考:STP环路避免实验(思科) 一,技术简介 Spanning Tree Protocol(STP),即生成树协议,是一种数据链路层协议。主要作用是防止二层环路,并自适应网络变化和故障…...
二、SpringBoot3 配置文件
本章概要 统一配置管理概述属性配置文件使用YAML 配置文件使用批量配置文件注入多环境配置和使用 2.1 统一配置管理概述 SpringBoot工程下,进行统一的配置管理,你想设置的任何参数(端口号、项目根路径、数据库连接信息等等)都集中到一个固定…...
二、阅读器的开发(初始)-- 2、阅读器开发
1、epubjs核心工作原理 1.1 epubjs的核心工作原理解析 epub电子书,会通过epubjs去实例化一个Book对象,Book对象会对电子书进行解析。Book对象可以通过renderTo方法去生成一个Rendition对象,Rendition主要负责电子书的渲染,通过R…...
【QT入门】 Qt自定义信号后跨线程发送信号
往期回顾: 【QT入门】 lambda表达式(函数)详解-CSDN博客 【QT入门】 Qt槽函数五种常用写法介绍-CSDN博客 【QT入门】 Qt实现自定义信号-CSDN博客 【QT入门】 Qt自定义信号后跨线程发送信号 由于Qt的子线程是无法直接修改ui,需要发送信号到ui线程进行修改…...
51单片机学习笔记7 串转并操作方法
51单片机学习笔记7 串转并操作方法 一、串转并操作简介二、74HC595介绍1. **功能**:2. **引脚**:3. **工作原理**:4. 开发板原理图(1)8*8 LED点阵:(2)74HC595 串转并: 三…...
微服务cloud--抱团取暖吗 netflix很多停更了
抱团只会卷,卷卷也挺好的 DDD 高内聚 低耦合 服务间不要有业务交叉 通过接口调用 分解技术实现的复杂性,围绕业务概念构建领域模型;边界划分 业务中台: 数据中台: 技术中台: 核心组件 eureka&#x…...
牛客笔试|美团2024春招第一场【测试方向】
第一题:小美的数组询问 小美拿到了一个由正整数组成的数组,但其中有一些元素是未知的(用 0 来表示)。 现在小美想知道,如果那些未知的元素在区间 [l, r] 范围内随机取值的话,数组所有元素之和的最小值和最大…...
Docker搭建LNMP环境实战(一):前言
缘起:不久前学习了Docker相关知识,并在Docker环境下学习了LNMP环境的搭建。由于网上的文章大多没有翔实、可行的案例,很多文章都是断章取义,所以,期间踩了太多太多的坑,初学者想要真正顺利地搭建一套环境起…...
SCI一区 | Matlab实现PSO-TCN-BiGRU-Attention粒子群算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测
SCI一区 | Matlab实现PSO-TCN-BiGRU-Attention粒子群算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测 目录 SCI一区 | Matlab实现PSO-TCN-BiGRU-Attention粒子群算法优化时间卷积双向门控循环单元融合注意力机制多变量时间序列预测预测效果基本介绍模型描述…...
界面控件DevExpress ASP.NET Ribbon组件 - 完美复刻Office 365体验!
无论用户是喜欢传统工具栏菜单外观、样式,还是想在下一个项目中复制Office 365 web UI,DevExpress ASP.NET都提供了所需要的工具,帮助用户打造更好的应用程序界面。 P.S:DevExpress ASP.NET Web Forms Controls拥有针对Web表单&a…...
vue2【详解】mixins —— 抽离公共逻辑
mixins 用于在 Vue 中便捷复用变量、方法、组件引用、生命周期等 使用方法 创建文件myMixin.js export const myMixin {data() {return {webName: 朝阳的博客}},created() {alert(欢迎来到${this.webName})},methods: {hi() {alert(欢迎来到${this.webName})}} }vue文件中引入…...
ArrayList的常用方法
ArrayList是Java中常用的动态数组类,它提供了一系列用于操作和管理数组的方法。下面是一些ArrayList常用方法的介绍: add()方法:向ArrayList中添加元素,可以指定位置添加元素或者在末尾添加元素。 ArrayList<String> list …...
ES-Hadoop:将Elasticsearch与Hadoop无缝集成的开源工具
hadoop 大数据技术之Hive(3)PyHive pyhdfs ES,Elasticsearch https://zhuanlan.zhihu.com/p/595505475?utm_id0 Hadoop hdfs 、hive、spark https://blog.51cto.com/u_16099278/6901638 ES-Hadoop:将Elasticsearch与Hadoop无缝集成的开源工…...
质量模型、软件测试流程和测试用例
质量模型 衡量一个优秀软件的维度 可以从功能性、性能、兼容性、易用性、安全、可靠性、可维护性、可移植性这几个方面去做软件测试,但咱们在正常测试中一般是选取前五项进行测试 测试流程 1、需求评审:确保各部门对需求的理解一致 2、测试计划编写&a…...
集简云新增“文本语音转换”功能,实现智能语音交互
为丰富人工智能领域的应用集成,为用户提供更便捷和智能化的信息获取和视觉创作方式,本周集简云上线了内置应用—文本语音转换。目前支持OpenAI TTS和TTS HD模型,实现文本语音高效智能转换,也可根据你的产品或品牌创建独特的神经网…...
图像处理领域专业术语
图像处理中的一些常见术语,涵盖了从基础概念到高级处理技术的各个方面。 以下是一些图像处理领域常用的专业术语及其解释: 像素(Pixel): 图像的最基本单元,每个像素都有一个或多个与其关联的数值࿰…...
Microsoft Edge 中的 Internet Explorer 模式解决ie禁止跳转到edge问题
作为网工,网络中存在很老的设备只能用ie浏览器访问打开,但是win10后打开Internet Explorer 会强制跳转到Edge 浏览器,且有人反馈不会关,为此找到了微软官方的Microsoft Edge 中的 Internet Explorer 模式,可以直接在Mi…...
2026届必备的五大AI论文工具横评
Ai论文网站排名(开题报告、文献综述、降aigc率、降重综合对比) TOP1. 千笔AI TOP2. aipasspaper TOP3. 清北论文 TOP4. 豆包 TOP5. kimi TOP6. deepseek 技术人工智能的发展速度飞快,论文AI类网站成了可辅助学术写作领域的重要工具&…...
【HTML动态交互实战】模拟股市波动可视化系统
1. 从零搭建股市波动可视化系统 最近在做一个金融数据分析的小项目,需要模拟股票价格波动并可视化展示。作为一个前端开发者,我第一时间想到用HTML5 Canvas来实现这个需求。下面就把我的实现思路和踩过的坑分享给大家。 先说说为什么要用Canvas而不是S…...
如何高效处理生命科学图像数据:Bio-Formats完全实战指南
如何高效处理生命科学图像数据:Bio-Formats完全实战指南 【免费下载链接】bioformats Bio-Formats is a Java library for reading and writing data in life sciences image file formats. It is developed by the Open Microscopy Environment. Bio-Formats is re…...
Fish Speech 1.5可部署方案:私有化语音合成服务搭建完整指南
Fish Speech 1.5可部署方案:私有化语音合成服务搭建完整指南 1. 项目概述与核心价值 Fish Speech 1.5是一个基于VQ-GAN和Llama架构的先进文本转语音模型,经过超过100万小时的多语言音频数据训练。这个模型最大的特点是能够提供高质量的语音合成服务&am…...
3层修复机制深度解析:Windows更新故障修复工具架构原理
3层修复机制深度解析:Windows更新故障修复工具架构原理 【免费下载链接】Reset-Windows-Update-Tool Troubleshooting Tool with Windows Updates (Developed in Dev-C). 项目地址: https://gitcode.com/gh_mirrors/re/Reset-Windows-Update-Tool Reset Wind…...
Cursor Free VIP:如何绕过限制免费解锁AI编程神器的完整方案
Cursor Free VIP:如何绕过限制免费解锁AI编程神器的完整方案 【免费下载链接】cursor-free-vip [Support 0.45](Multi Language 多语言)自动注册 Cursor Ai ,自动重置机器ID , 免费升级使用Pro 功能: Youve reached yo…...
知识星球内容归档终极方案:5步打造个人数字图书馆
知识星球内容归档终极方案:5步打造个人数字图书馆 【免费下载链接】zsxq-spider 爬取知识星球内容,并制作 PDF 电子书。 项目地址: https://gitcode.com/gh_mirrors/zs/zsxq-spider 在数字化学习时代,知识星球汇聚了大量优质内容&…...
Qwen3-ASR-0.6B在会议记录场景落地:本地化语音转写提升企业数据安全合规性
Qwen3-ASR-0.6B在会议记录场景落地:本地化语音转写提升企业数据安全合规性 1. 项目背景与价值 在企业日常运营中,会议记录是必不可少的工作环节。传统的会议记录方式要么依赖人工记录效率低下,要么使用云端语音识别服务存在数据安全风险。特…...
WordPress NextMove Lite 插件权限绕过漏洞利用工具 (CVE-2024-25092)
CVE-2024-25092 漏洞利用工具 项目描述 本项目是针对 CVE-2024-25092 漏洞的自动化利用脚本。该漏洞存在于 WordPress XLPlugins NextMove Lite 插件(版本号 ≤ 2.17.0)中,由于缺少授权检查,导致具有订阅者(Subscriber…...
安全设备-NIDS入侵检测系统
免责声明: 本文内容仅用于安全研究与学习,请在合法授权的环境中使用,严禁用于任何非法用途。因使用不当造成的后果由使用者自行承担,并应遵守相关法律法规。 IDS-入侵检测系统 基于主机的入侵检测系统(HIDS)基于网络的…...
