网络编程作业day7
作业项目:基于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);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;
}
//用户登录操作函数
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;
}
项目作业-基于udp的聊天室
思维导图:

相关文章:
网络编程作业day7
作业项目:基于UDP的聊天室 服务器代码: #include <myhead.h>//定义客户信息结构体 typedef struct magtye {char type; //消息类型char name[100]; //客户姓名char text[1024]; //客户发送聊天信息 }msg_t;//定义结构体存储…...
【Vision Pro杀手级应用】3D音乐会/演唱会,非VR视频播放的形式,而是实实在在的明星“全息”形象,在你的面前表演
核心内容形式:体积视频 参考对标案例深度解读: 体积视频,这一全新的内容形式,正在引领我们进入一个前所未有的四维体验时代。它将传统的演艺形式推向了新的高度,让我们能够更加深入地沉浸在虚拟世界中,感受前所未有的视听盛宴。 在这一领域,有一个引人注目的案例,那…...
变频器学习
西门子变频器 SINAMICS V20 入门级变频器 SINAMICS G120C...
Linux Ubuntu系统安装MySQL并实现公网连接本地数据库【内网穿透】
文章目录 前言1 .安装Docker2. 使用Docker拉取MySQL镜像3. 创建并启动MySQL容器4. 本地连接测试4.1 安装MySQL图形化界面工具4.2 使用MySQL Workbench连接测试 5. 公网远程访问本地MySQL5.1 内网穿透工具安装5.2 创建远程连接公网地址5.3 使用固定TCP地址远程访问 前言 本文主…...
0048__Unix传奇
Unix传奇 (上篇)_unix传奇(上篇)-CSDN博客 Unix传奇 (下篇)-CSDN博客 Unix现状与未来——CSDN对我的采访_nuix邮件系统行业地位-CSDN博客...
蓝桥杯-排序
数组排序 Arrays.sort(int[] a) 这种形式是对一个数组的所有元素进行排序,并且时按从小到大的顺序。 package Work;import java.util.*;public class Imcomplete {public static void main(String args[]) {int arr[]new int [] {1,324,4,5,7,2};Arrays.sort(arr)…...
计算机设计大赛 深度学习的视频多目标跟踪实现
文章目录 1 前言2 先上成果3 多目标跟踪的两种方法3.1 方法13.2 方法2 4 Tracking By Detecting的跟踪过程4.1 存在的问题4.2 基于轨迹预测的跟踪方式 5 训练代码6 最后 1 前言 🔥 优质竞赛项目系列,今天要分享的是 基于深度学习的视频多目标跟踪实现 …...
高性能JSON框架之FastJson的简单使用
高性能JSON框架之FastJson的简单使用、 1.前言 1.1.FastJson的介绍: JSON协议使用方便,越来越流行,JSON的处理器有很多,这里我介绍一下FastJson,FastJson是阿里的开源框架,被不少企业使用,是一个极其优秀的Json框架,Github地址: FastJson 1.2.FastJson的特点: 1.F…...
★判断素数的几种方法(由易到难,由慢到快)
素数的定义: 素数,又称为质数,指的是“大于1的整数中,只能被1和这个数本身整除的数”。换句话说,素数是只有两个正约数(1和本身)的自然数。素数在数论中有着重要的地位,且素数的个数…...
vue svelte solid 虚拟滚动性能对比
前言 由于svelte solid 两大无虚拟DOM框架,由于其性能好,在前端越来越有影响力。 因此本次想要验证,这三个框架关于实现表格虚拟滚动的性能。 比较版本 vue3.4.21svelte4.2.12solid-js1.8.15 比较代码 这里使用了我的 stk-table-vue(np…...
IDEA中新增文件,弹出框提示是否添加到Git点错了,怎么重新设置?
打开一个配置了Git的项目,新增一个文件,会弹出下面这个框。提示是否将新增的文件交给Git管理。 一般来说,会选择ADD,并勾选Dont ask agin,添加并不再询问。如果不小心点错了,可在IDEA中重新设置(…...
LV15 day5 字符设备驱动读写操作实现
一、读操作实现 ssize_t xxx_read(struct file *filp, char __user *pbuf, size_t count, loff_t *ppos); 完成功能:读取设备产生的数据 参数: filp:指向open产生的struct file类型的对象,表示本次read对应的那次open pbuf&#…...
Uninty 鼠标点击(摄像机发出射线-检测位置)
平面来触发碰撞,胶囊用红色材质方便观察。 脚本挂载到胶囊上方便操作。 目前实现的功能,鼠标左键点击,胶囊就移动到那个位置上。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c6 : MonoBe…...
描述下Vue自定义指令
描述下Vue自定义指令 (1)自定义指令基本内容(2)使用场景(3)使用案例 在 Vue2.0 中,代码复用和抽象的主要形式是组件。然而,有的情况下,你仍然需要对普通 DOM 元素进行底层…...
2024.3.7
作业: 1、OSI的七层网络模型有哪些,每一层有什么作用? (1)应用层 负责处理不同应用程序之间的通信,需要满足提供的协议,确保数据发送方和接收方的正确 (2)表示层…...
this.$watch 侦听器 和 停止侦听器
使用组件实例的$watch()方法来命令式地创建一个侦听器; 它还允许你提前停止该侦听器 语法:this.$watch(data, method, object) 1. data:侦听的数据源,类型为String 2. method:回调函数&#x…...
P1030 [NOIP2001 普及组] 求先序排列题解
题目 给出一棵二叉树的中序与后序排列。求出它的先序排列。(约定树结点用不同的大写字母表示,且二叉树的节点个数≤8)。 输入输出格式 输入格式 共两行,均为大写字母组成的字符串,表示一棵二叉树的中序与后序排列。…...
【分布式】NCCL Split Tree kernel内实现情况 - 06
相关系列 【分布式】NCCL部署与测试 - 01 【分布式】入门级NCCL多机并行实践 - 02 【分布式】小白看Ring算法 - 03 【分布式】大模型分布式训练入门与实践 - 04 目录 相关系列概述1.1 Tree1.2 double binary tree初始化和拓扑2.1 Tree的初始化与差异2.2 ncclGetBtreeKernel内部…...
C语言深入学习 --- 4.自定义类型(结构体+枚举+联合)
第四章 自定义类型:结构体,枚举,联合 结构体 结构体类型的声明 结构的自引用 结构体变量的定义和初始化 结构体的内存对齐 结构体实现位段(位段的填充 和 可移植性) 枚举 枚举类型的定义 枚举的优点 枚举的使…...
AI自然语言中默认上下文长度4K 几K是什么意思?
环境: 4K 问题描述: AI自然语言中默认上下文长度4K 几K是什么意思? 解决方案: 在自然语言处理中,“k” 表示 “千”,是一种简写方式。当我们说 “4k” 时,实际上指的是 “4,000”。在上下文…...
告别IDE切换!在VS2022里用上C++ Builder的智能提示(保姆级路径配置)
在VS2022中无缝集成C Builder智能提示的终极指南 对于长期使用C Builder进行Windows桌面开发的工程师来说,Visual Studio 2022的现代化界面和强大调试功能一直是个诱人的存在。但频繁在两个IDE之间切换不仅打断工作流,还会显著降低开发效率。本文将揭示如…...
本地Cookie管理终极指南:Get cookies.txt LOCALLY完全解析
本地Cookie管理终极指南:Get cookies.txt LOCALLY完全解析 【免费下载链接】Get-cookies.txt-LOCALLY Get cookies.txt, NEVER send information outside. 项目地址: https://gitcode.com/gh_mirrors/ge/Get-cookies.txt-LOCALLY 在当今数字时代,…...
数字电路模块化设计的艺术:Logisim-evolution中的层次化抽象实践
数字电路模块化设计的艺术:Logisim-evolution中的层次化抽象实践 【免费下载链接】logisim-evolution Digital logic design tool and simulator 项目地址: https://gitcode.com/gh_mirrors/lo/logisim-evolution 在数字电路设计的世界里,复杂系统…...
LSPatch:无需Root的Android应用模块化终极指南
LSPatch:无需Root的Android应用模块化终极指南 【免费下载链接】LSPatch LSPatch: A non-root Xposed framework extending from LSPosed 项目地址: https://gitcode.com/gh_mirrors/ls/LSPatch 你是否曾经羡慕iOS的越狱插件,却因Android设备未ro…...
Verilog函数封装:提升代码复用与维护性的组合逻辑设计实践
1. 项目概述:为什么要在Verilog中“封装”行为逻辑?写Verilog代码,尤其是行为级描述,最怕的就是看到一段几乎一模一样的组合逻辑或者运算过程,在模块的不同角落里反复出现。比如,一个模块里可能需要三次把输…...
抖音无水印下载终极指南:douyin-downloader完整教程
抖音无水印下载终极指南:douyin-downloader完整教程 【免费下载链接】douyin-downloader A practical Douyin downloader for both single-item and profile batch downloads, with progress display, retries, SQLite deduplication, and browser fallback support…...
FiveM 新手服主必看:开源与托管(闭源)到底是什么
大家好,我是难言,你们的老朋友了。在 FiveM 生态深耕多年,我发现许多新手服主对开源与托管(闭源)插件的概念认知模糊,甚至无法区分二者的核心差异。更不合理的是,圈内逐渐形成鄙视链,…...
矩阵键盘原理与实战:从扫描算法到Arduino/CircuitPython驱动指南
1. 项目概述:为什么我们需要矩阵键盘? 在嵌入式项目里,给设备加几个按钮是再常见不过的需求。但如果你需要10个、12个甚至16个独立的按键呢?按照传统思路,一个按键对应一个微控制器的数字输入引脚,那你的Ar…...
aivectormemory:轻量级向量记忆库,为AI应用开发提供灵活存储方案
1. 项目概述:向量记忆库的“新玩家”最近在折腾AI应用开发,特别是涉及到需要让模型“记住”大量私有知识或者进行复杂对话的场景时,一个绕不开的核心组件就是向量数据库。大家熟知的Pinecone、Weaviate、Milvus这些方案固然强大,但…...
音频智能切片工具:快速解放双手的终极音频分割解决方案
音频智能切片工具:快速解放双手的终极音频分割解决方案 【免费下载链接】audio-slicer A simple GUI application that slices audio with silence detection 项目地址: https://gitcode.com/gh_mirrors/aud/audio-slicer 还在为处理冗长的音频文件而烦恼吗&…...
