当前位置: 首页 > news >正文

UDP网络聊天室

项目需求:

1.如果有用户登录,其他用户可以收到这个人的登录信息

2.如果有人发送信息,其他用户可以收到这个人的群聊信息

3.如果有人下线,其他用户可以收到这个人的下线信息

4.服务器可以发送系统信息

客户端代码

#include<myhead.h>
//用户链表结构体
typedef struct Node
{char usrName[20];//用户名struct sockaddr_in cin;//客户端地址struct Node *next;//指针
}Node,*NodePtr;
//消息结构体
typedef struct msgTyp
{char type;//消息类型char usrName[20];//用户名char msgText[1024];//消息内容
}msgTyp;
//创建头结点
NodePtr create_Node(struct sockaddr_in sin)
{NodePtr L=(NodePtr)malloc(sizeof(Node));if(NULL==L){printf("创建失败\n");return NULL;}strcpy(L->usrName,"**system**");//服务器名字L->cin=sin;//服务器地址L->next=NULL;return L;
}
//申请结点
NodePtr apply_Node()
{NodePtr p=(NodePtr)malloc(sizeof(Node));if(NULL==p){printf("创建失败\n");return NULL;}struct sockaddr_in cin;socklen_t addrlen=sizeof(cin);memset(&cin,0,addrlen);strcpy(p->usrName,"");p->cin=cin;p->next=NULL;return p;
}
//判空
int list_empty(NodePtr L)
{return L->next==NULL;
}
//尾插
int inser_tail(NodePtr L,struct sockaddr_in cin,msgTyp M)
{if(NULL==L){printf("链表不合法\n");return -1;}NodePtr p=apply_Node();strcpy(p->usrName,M.usrName);p->cin=cin;NodePtr t=L;while(t->next!=NULL){t=t->next;}t->next=p;return 0;
}
//查找结点位置
int search_Node(NodePtr L,struct sockaddr_in cin)
{if(NULL==L||list_empty(L)){printf("查找失败\n");return -1;}NodePtr q=L->next;int i=1;//判断端口和ip地址while(q->cin.sin_addr.s_addr!=cin.sin_addr.s_addr||q->cin.sin_port!=cin.sin_port){i++;q=q->next;}return i;//返回位置
}
//按位置删除结点
int delete_Node(NodePtr L,struct sockaddr_in cin)
{if(NULL==L||list_empty(L)){printf("删除失败\n");return -1;}int i=search_Node(L,cin);//要删除的结点位置NodePtr p=L;int j=1;//找到要删除结点while(j<i){p=p->next;j++;}NodePtr q=p->next;p->next=q->next;free(q);q=NULL;return 0;
}
//头删
int delete_head(NodePtr L)
{if(NULL==L||list_empty(L)){printf("删除失败\n");return -1;}NodePtr p=L->next;L->next=p->next;free(p);p=NULL;return 0;
}
//销毁链表
int destroy(NodePtr L)
{if(NULL==L){printf("销毁失败\n");return -1;}while(!list_empty(L)){delete_head(L);}free(L);L=NULL;return 0;
}int main(int argc, char const *argv[])
{//判断输入个数if(argc!=3){printf("input error\n");return -1;}//创建服务器套接字int sfd=socket(AF_INET,SOCK_DGRAM,0);if(sfd==-1){perror("socket error");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;}//创建头结点NodePtr L=create_Node(sin);if(NULL==L){return -1;}//客户端struct sockaddr_in cin;socklen_t addrlen=sizeof(cin);//创建子进程pid_t pid=fork();//子进程工作内容if(pid==0){msgTyp msg;//定义消息变量char buf[1044]="";//存放数据while(1){//初始化memset(&msg,0,sizeof(msg));bzero(buf,sizeof(buf));//接收客户端消息recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&addrlen);//判断消息类型switch(msg.type){//d类型消息登录case 'd':{//服务器输出登录成功printf("%s [%s:%d]登录成功\n",msg.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));//登录成功消息存入bufsprintf(buf,"-----%s登录成功-----",msg.usrName);//遍历链表发送NodePtr p=L->next;while(p!=NULL){sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&p->cin,sizeof(p->cin));p=p->next;}//插入链表inser_tail(L,cin,msg);}break;//t类型消息发送消息case 't':{//判断端口和地址是否为服务器,服务器输出if(L->cin.sin_port!=cin.sin_port||L->cin.sin_addr.s_addr!=cin.sin_addr.s_addr){printf("%s [%s:%d]%s\n",msg.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port),msg.msgText);}//消息存入buf   sprintf(buf,"%s:%s",msg.usrName,msg.msgText);  //遍历链表NodePtr p=L->next;while(p!=NULL){//判断端口和地址是否和发送过来的客户端一样,不是则发送消息if(p->cin.sin_port!=cin.sin_port||p->cin.sin_addr.s_addr!=cin.sin_addr.s_addr){sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&p->cin,sizeof(p->cin));}p=p->next;}}break;//q类型消息退出case 'q':{//服务器输出printf("%s [%s:%d]退出成功\n",msg.usrName,inet_ntoa(cin.sin_addr),ntohs(cin.sin_port));//已下线消息存入bufsprintf(buf,"-----%s已下线-----",msg.usrName);delete_Node(L,cin);//删除该结点//遍历链表发送消息NodePtr p=L->next;while(p!=NULL){sendto(sfd,buf,sizeof(buf),0,(struct sockaddr*)&p->cin,sizeof(p->cin));p=p->next;}}break;//消息类型错误default:printf("接收消息类型错误\n");}}}//父进程工作内容if(pid>0){msgTyp msg;//定义消息类型变量while(1){memset(&msg,0,sizeof(msg));//初始化fgets(msg.msgText,sizeof(msg.msgText),stdin);//服务器输入内容存入消息内容msg.msgText[strlen(msg.msgText)-1]=0;//判断是否退出if(strcmp(msg.msgText,"quit")==0){break;}msg.type='t';//消息类型为tstrcpy(msg.usrName,"**system**");//服务器名字//发送给子进程服务器sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin));}}destroy(L);//销毁链表kill(pid,SIGKILL);//杀死子进程wait(NULL);//回收close(sfd);//关闭套接字return 0;
}

客户端代码

#include<myhead.h>
//消息结构体
typedef struct msgTyp
{char type;char usrName[20];char msgText[1024];
}msgTyp;
int main(int argc, char const *argv[])
{//判断输入个数if(argc!=3){printf("input error\n");return -1;}//创建套接字int cfd=socket(AF_INET,SOCK_DGRAM,0);if(cfd==-1){perror("socket error");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]);socklen_t sin_addrlen=sizeof(sin);msgTyp msg;//定义消息变量//存入姓名printf("请输入姓名:");scanf("%s",msg.usrName);getchar();strcpy(msg.msgText,"");//初始化消息内容msg.type='d';//d类型消息//发送给服务器sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_addrlen);//创建子进程pid_t pid=fork();//子进程工作内容if(pid==0){char buf[1024]="";//存消息while(1){bzero(buf,sizeof(buf));//初始化//接收消息recvfrom(cfd,buf,sizeof(buf),0,(struct sockaddr*)&sin,&sin_addrlen);printf("%s\n",buf);//输出}}//父进程工作内容if(pid>0){while(1){bzero(msg.msgText,sizeof(msg.msgText));//初始化消息内容fgets(msg.msgText,sizeof(msg.msgText),stdin);//输入消息存入msg.msgText[strlen(msg.msgText)-1]=0;//判断是否退出if(strcmp(msg.msgText,"quit")==0){msg.type='q';//q类型消息//发送消息给服务器sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin));break;}msg.type='t';//t类型消息sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sizeof(sin));}}kill(pid,SIGKILL);//杀死子进程wait(NULL);//回收close(cfd);//关闭套接字return 0;
}

运行结果


http://www.mrgr.cn/news/4118.html

相关文章:

  • appium下载及安装
  • el-form表单在循环里如何写rules表单校验,解决办法
  • Lua 调试(Debug)
  • SAM 2——视频和图像实时实例分割的全新开源模型
  • 【前端基础篇】CSS基础速通万字介绍(上篇)
  • 【计算机网络】网络基础
  • OpenAI Embeddings API: How to extract the embedding vector?
  • SVG中的paint-order属性实现文字描边
  • Hadoop 中的大数据技术:Zookeeper安装 (2)
  • 05创建型设计模式——原型模式
  • 汇凯贵金属:金子在家怎么清洗才干净
  • 非常nice! IDEA远程Debug调试程序
  • epoll机制中最核⼼的数据结构是什么?
  • 并查集在哪些具体应用中最常用
  • 计算机相关法律法规及违规案例
  • 机器学习在旅游业的革新之旅
  • ubuntu18.04更改系统语言及换源的方法步骤
  • 深入解析css-学习小结
  • C语言 | Leetcode C语言题解之第342题4的幂
  • PostgreSQL的pg_dump中 --inserts参数测试