UDP聊天室

1.头文件

/*===============================================
*   文件名称:UDP.h
*   创 建 者:crx    
*   创建日期:2023年09月3日
*   描    述:
================================================*/
#ifndef _UDP_H
#define _UDP_H#include <stdio.h>
#include <sys/types.h>          /* See NOTES */
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>  
#include <arpa/inet.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>typedef struct node{            //链表节点保存用户地址结构体信息struct sockaddr_in caddr;  struct node *next;   
}Node,*Pnode;typedef struct mesg{          //用户状态、姓名、消息char state;  char name[20];  char text[60];  
}Mesg;enum state{         //状态:登录、转发、下线Login,  Relay,   Quit,   
};//创建头节点
Pnode create_node();
//插入,登录
int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg);
//转发
void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg);
//删除,下线
int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg);#endif

2.服务器

/*===============================================*   文件名称:UDPs.c*   创 建 者:crx     *   创建日期:2023年09月3日*   描    述:================================================*/
#include "UDP.h"int main(int argc, char *argv[])
{//1.创建套接字int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");return -1;}//2.绑定struct sockaddr_in saddr;saddr.sin_family = AF_INET;saddr.sin_port = htons(8181);saddr.sin_addr.s_addr = INADDR_ANY;int bindfd = bind(sockfd,(struct sockaddr *)&saddr,sizeof(saddr));if(-1 == bindfd){perror("bind");return -1;}//3.准备保存客户端地址结构体,等待登录printf("等待登录....\n");struct sockaddr_in caddr;               socklen_t addrlen = sizeof(caddr);Mesg msg;//4.创建头节点Pnode p = create_node();    Pnode q = p;Pnode temp = p;while(1){memset(&caddr,0,sizeof(caddr));  //5.接收用户登录信息recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&caddr,&addrlen); //6.根据用户状态执行对应操作//msg.state = Login
//用户登录,链表插入用户信息
//判断链表是否为空,为空则插入用户
//链表不为空,判断是否是链表中已有用户,不是则插入用户信息
//转发登录消息给其他在线用户if(msg.state == Login)     {if(NULL == q->next){           insert_node(p,caddr,msg);   strcpy(msg.text,"已登录!");}else{   temp = p->next;while(temp){        if(temp->caddr.sin_port == caddr.sin_port && temp->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr)break;        elsetemp = temp->next;}if(NULL == temp){insert_node(p,caddr,msg);strcpy(msg.text,"已登录!");relay(sockfd,p,caddr,msg);}}}//msg.state = Relay
//转发用户信息给其他在线用户if(msg.state == Relay)   {relay(sockfd,p,caddr,msg);}//msg.state = Quit
//用户下线
//链表中删除用户信息
//转发用户下线信息给其他用户if(msg.state == Quit)        {delete_node(p,caddr,msg);strcpy(msg.text,"已下线");relay(sockfd,p,caddr,msg);}}return 0;
} //创建头节点
Pnode create_node()
{            Pnode p = (Pnode)malloc(sizeof(Node));if(NULL == p){perror("malloc");return NULL;}p->next = NULL;return p;
}//插入,登录
int insert_node(Pnode p,struct sockaddr_in caddr,Mesg msg)
{ if(NULL == p){return -1;}Pnode new = (Pnode)malloc(sizeof(Node));if(NULL == new){perror("malloc");return -2;}new->next = p->next;p->next = new;new->caddr = caddr;printf("已登录!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));return 1;
}//转发
void relay(int sockfd,Pnode p,struct sockaddr_in caddr,Mesg msg)        {while(p->next){    p = p->next;if(p->caddr.sin_port == caddr.sin_port && p->caddr.sin_addr.s_addr == caddr.sin_addr.s_addr){continue;    }else{sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&(p->caddr),sizeof(p->caddr)); }}
}//删除,下线
int delete_node(Pnode p,struct sockaddr_in caddr,Mesg msg)  
{if(NULL == p){return -1;}while(p->next){if(memcmp(&(p->next->caddr),&caddr,sizeof(caddr)) == 0){Pnode q = p->next;p->next = q->next;free(q);break;}else{p = p->next;}}printf("已下线!name:%s,ip:%s,port:%d\n",msg.name,inet_ntoa(caddr.sin_addr),ntohs(caddr.sin_port));
}

3.客户端

/*===============================================*   文件名称:UDPc.c*   创 建 者:crx     *   创建日期:2023年09月3日*   描    述:================================================*/
#include "UDP.h"int main(int argc, char *argv[])
{//1.创建套接字int sockfd = socket(AF_INET,SOCK_DGRAM,0);if(-1 == sockfd){perror("socket");return -1;}//2.服务器地址struct sockaddr_in saddr;   saddr.sin_family = AF_INET;saddr.sin_port = htons(8181);saddr.sin_addr.s_addr = inet_addr("192.168.17.225");//3.创建用户Mesg msg;    //4.运行后触发msg.state = Login//登录填写用户名//发送给服务器登录信息转发登录消息操作printf("登录\n");   msg.state = Login;printf("请输入用户名:\n");fgets(msg.name,20,stdin);printf("******************************************\n");if(msg.name[strlen(msg.name)-1] == '\n')msg.name[strlen(msg.name) -1] = '\0';//发送用户登录消息if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))) {perror("sendto");return -1;}//5.创建子进程pid_t pid = fork();//6.子进程循环接收其他用户消息并打印发送人及信息if(pid == 0)  {while(1){socklen_t addrlen = sizeof(saddr);recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,&addrlen);printf("~%s~ : %s\n",msg.name,msg.text);}} else{//7.父进程获取用户终端输入到用户消息中while(1){fgets(msg.text,sizeof(msg.text),stdin);    if(msg.text[strlen(msg.text)-1] == '\n')msg.text[strlen(msg.text) -1] = '\0';//8.处理终端输入//终端输入Quit则触发msg.state = Quit
//发送给服务器下线信息执行对应操作
//使用SIGKILL强制结束进程if(strcmp(msg.text,"Quit") == 0)  {msg.state = Quit;if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))){perror("sendto");return -1;}kill(pid,SIGKILL); wait(NULL);exit(0);}
//终端输入不是Quit则触发msg.state = Relay
//发送给服务端执行转发操作else{msg.state = Relay;  }if(-1 == sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr *)&saddr,sizeof(saddr))){perror("sendto");return -1;}}}close(sockfd);return 0;
}

4.makefile

all:UDPs UDPc
UDPs:UDPs.cgcc  UDPs.c -o UDPs
UDPc:UDPc.cgcc  UDPc.c -o UDPc
clean:rm UDPs UDPc

5.结果

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

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

相关文章

TypeScript断言

什么是断言&#xff1f; 一个编译时语法&#xff0c;用于告诉编译器用户比编译器更加确定变量的类型&#xff0c;进而解除编译错误&#xff0c;类型断言有点类似于其他语言的类型转换&#xff0c;但它没有运行时的影响&#xff0c;只是在编译阶段起作用。所以&#xff0c;即使通…

QT Day5思维导图

聊天室代码&#xff1a; #include "cli.h" #include "ui_cli.h"Cli::Cli(QWidget *parent): QWidget(parent), ui(new Ui::Cli) {ui->setupUi(this);socket new QTcpSocket(this);connect(socket,&QTcpSocket::connected,this,&Cli::connect_…

2023年全国大学生数学建模B题

多波束测线问题 1.问题提出 单波束测深是利用声波在水中的传播特性来测量水体深度的技术。声波在均匀介质中作匀 速直线传播&#xff0c;在不同界面上产生反射&#xff0c;利用这一原理&#xff0c;从测量船换能器垂直向海底发射声波信号&#xff0c;并记录从声波发射到信号接…

C#开发的OpenRA游戏之系统参数选项按钮

C#开发的OpenRA游戏之系统参数选项按钮 前面分析了信标按钮,从图上可以看到,靠右边的按钮,就是系统参数选项按钮: 这个按钮与前面三个按钮是不一样的,虽然它们在排列位置上是放在一起,但是处理的方法方式是不一样的,因为这个选项按钮,并不需要发命令给服务器,再返回来…

《Effective STL》读书笔记(二):vector和string

vector 和 string 优先于动态分配数组 当使用new动态分配内存时&#xff0c;我们需要关注以下内容 必须保证动态分配的内存会被delete&#xff0c;否则会造成资源泄露必须确保使用了正确的delete形式。如果分配了单个对象&#xff0c;则必须使用delete&#xff1b;如果分配了…

Python实现猎人猎物优化算法(HPO)优化卷积神经网络分类模型(CNN分类算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 猎人猎物优化搜索算法(Hunter–prey optimizer, HPO)是由Naruei& Keynia于2022年提出的一种最新的…

浅谈能源汽车下乡充电桩建设优化建议及解决方案

1.趋势分析 新能源汽车下乡已经成为提振汽车市场表现、推动汽车行业发展的重要措施。国家发改委日前也提出&#xff0c;汽车消费是支撑消费的“大头”&#xff0c;将加快推进充电桩和城市停车设施建设&#xff0c;大力推动新能源汽车下乡&#xff0c;鼓励汽车企业开发更适宜县…

将目标检测项目移植到linux上出现OSERROR

在windows上运行项目正常&#xff0c;但是在centos9上运行出现找到资源&#xff0c;第一次遇到这个问题&#xff0c;通过代码回找&#xff0c;一步一步发现&#xff0c;读取数据没问题&#xff0c;但是在预测的时候无法读取&#xff0c;查到的资料 说明显示字体问题&#xff0c…

十八、MySQL添加外键?

1、外键 外键是用来让两张表的数据之间建立联系&#xff0c;从而保证数据的一致性和完整性。 注意&#xff0c;父表被关联的字段类型&#xff0c;必须和子表被关联的字段类型一致。 2、实际操作 &#xff08;1&#xff09;初始化两张表格&#xff1a; 子表&#xff1a; 父…

【Apollo学习笔记】——规划模块TASK之PIECEWISE_JERK_NONLINEAR_SPEED_OPTIMIZER(二)

文章目录 TASK系列解析文章OptimizeByNLP1.get_nlp_info()定义问题规模2.get_bounds_info()定义约束边界约束3.get_starting_point()定义初值4.eval_f()求解目标函数5.eval_grad_f()求解梯度6.eval_g()求解约束函数7.eval_jac_g()求解约束雅可比矩阵8.eval_h()求解黑塞矩阵9. f…

刷题笔记18——数组查缺补漏、二分搜索变体

人就是这样的&#xff0c;想来想去&#xff0c;犹豫来犹豫去&#xff0c;觉得自己没有准备好&#xff0c;勇气没攒够&#xff0c;其实只要迈出去了那一步&#xff0c;就会发现其实所有的一切&#xff0c;早就准备好了。——巫哲Q《撒野》 528. 按权重随机选择 轮盘赌 class S…

synchronized 关键字

synchronized是Java中的关键字&#xff0c;它用于实现同步访问共享资源&#xff0c;可解决共享资源竞争问题&#xff0c;以确保多个线程之间共享资源访问的正确性。当一个方法或代码块被声明为synchronized时&#xff0c;只有一个线程可以执行该方法或代码块。其他尝试访问该方…