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

学习嵌入式第三十六天

文章目录

  • 网络聊天室
    • 1.实现原理
    • 2.实现步骤
      • 1.客户端
        • 1.客户端1需要处理的情况
        • 2.客户端...需要处理的情况
      • 2.服务器
      • 3.需要用到的一些知识
        • 1.链表
        • 2.结构体和枚举
    • 3.具体实现
      • 1.链表所依赖的头文件
      • 2.链表用到的相关的函数
      • 3.UDP连接需要的头文件
      • 4.客户端
      • 5.服务器

网络聊天室

1.实现原理

  • 服务器通过UDP协议将接入的客户端汇总起来,并将消息转发出去
  • 客户端分别有聊天,下线以及登录三个状态

2.实现步骤

1.客户端

1.客户端1需要处理的情况
  1. 客户端与服务器端建立连接
  2. 向服务器发送消息
  3. 当有其余客户端接入聊天室,需要接收其余客户端发来的消息
  4. 客户端与服务器断开连接
2.客户端…需要处理的情况
  1. 客户端与服务器建立连接
  2. 向服务器发送消息
  3. 接收其余客户端发来的消息
  4. 客户端与服务器端断开连接

2.服务器

  1. 服务器接收到客户端上线的消息并将其保存,将这个客户端上线的消息转发给所有的客户端
  2. 服务器接收客户端发来的消息,并将这个消息转发给所有客户端
  3. 服务器接收客户端下线的消息,并将这个客户端下线的消息转发给其余的客户端

3.需要用到的一些知识

1.链表
  • 链表可以将每个客户端的地址信息,状态信息打包保存下来,方便管理以及后续客户端的加入
  • 在发送消息的时候,可以用遍历的思想将链表遍历,每到一个节点就可以将要发送的消息转发给地址对应的客户端
  • 当服务器收到有客户端要退出的消息,就可以使用函数删掉这个节点
2.结构体和枚举
  • 由于服务器和客户端都需要不断地发送接收不同客户端发送的消息,可以在头文件中定义一个存储状态,消息和昵称信息的结构体,这样可以将所有信息打包发送

    typedef struct msg{enum MSG_TYPE type;char name[20];char text[1024];
    }msg_t;
    
  • 也可以使用枚举将每个客户端的状态定义出来,方便使用

    enum MSG_TYPE{LOGIN,CHAT,QUIT,
    };
    

3.具体实现

1.链表所依赖的头文件

#ifndef _DOUBLELIST_H
#define _DOUBLELIST_H#include <netinet/in.h>
#include"head.h"typedef struct cliaddr{struct sockaddr_in addr;int stat;struct cliaddr *ppre;struct cliaddr *pnext;
}linknode;extern linknode *create_empty_linklist(void);
extern int insert_head_linklist(linknode *phead,struct sockaddr_in tmpdata);
extern int show_hi_linklist(linknode *phead,msg_t *pmsg,int serfd);
extern int show_bye_linklist(linknode *phead,msg_t *pmsg,int serfd);
extern int destory_linklist(linknode **pphead);
extern linknode *find_linklist(linknode *phead,struct sockaddr_in tmpdata);
extern int update_linklist(linknode *phead, struct sockaddr_in olddata, struct sockaddr_in
newdata);
extern int delete_linklist(linknode *phead, struct sockaddr_in tmpdata);
extern int send_linklist(linknode *phead,msg_t *pmsg,int serfd);#endif

2.链表用到的相关的函数

#include<stdio.h>
#include"doublelist.h"
#include<stdlib.h>
#include <netinet/in.h>
#include"head.h"linknode *create_empty_linklist(void){linknode *ptmpnode = NULL;ptmpnode = malloc(sizeof(linknode));if(ptmpnode == NULL){perror("fail to malloc");return NULL;}ptmpnode->ppre = NULL;ptmpnode->pnext = NULL;ptmpnode->stat = 0; // 初始化statreturn ptmpnode;
}
int insert_head_linklist(linknode *phead,struct sockaddr_in tmpdata){linknode *ptmpnode = NULL;ptmpnode = malloc(sizeof(linknode));if(ptmpnode == NULL){perror("fail to malloc");return -1;}ptmpnode->addr = tmpdata;ptmpnode->stat = 0; // 初始化statptmpnode->pnext = phead->pnext;phead->pnext = ptmpnode;ptmpnode->ppre = phead;if(ptmpnode->pnext != NULL){ptmpnode->pnext->ppre = ptmpnode;}return 0;
}int show_hi_linklist(linknode *phead,msg_t *pmsg,int serfd){linknode *ptmpnode = NULL;ptmpnode = phead->pnext;while(ptmpnode != NULL){strcpy(pmsg->text,"login\r\n");sendto(serfd,pmsg,sizeof(msg_t),0,(const struct sockaddr*)&ptmpnode->addr,sizeof(ptmpnode->addr));ptmpnode = ptmpnode->pnext;}return 0;
}
int send_linklist(linknode *phead,msg_t *pmsg,int serfd){linknode *ptmpnode = NULL;ptmpnode = phead->pnext;while(ptmpnode != NULL){sendto(serfd,pmsg,sizeof(msg_t),0,(const struct sockaddr*)&ptmpnode->addr,sizeof(ptmpnode->addr));ptmpnode = ptmpnode->pnext;}return 0;
}
int show_bye_linklist(linknode *phead,msg_t *pmsg,int serfd){linknode *ptmpnode = NULL;ptmpnode = phead->pnext;while(ptmpnode != NULL){strcpy(pmsg->text,"quit\r\n");sendto(serfd,pmsg,sizeof(msg_t),0,(const struct sockaddr*)&ptmpnode->addr,sizeof(ptmpnode->addr));ptmpnode = ptmpnode->pnext;}return 0;
}linknode *find_linklist(linknode *phead,struct sockaddr_in tmpdata){linknode *ptmpnode = NULL;ptmpnode = phead->pnext;while(ptmpnode != NULL){if(memcmp(&ptmpnode->addr, &tmpdata, sizeof(struct sockaddr_in)) == 0){// 找到后返回指针return ptmpnode;}ptmpnode = ptmpnode->pnext;}return NULL;
}int delete_linklist(linknode *phead,struct sockaddr_in tmpdata){linknode *ptmpnode = NULL;linknode *pfreenode = NULL;ptmpnode = phead->pnext;while(ptmpnode != NULL){if(memcmp(&ptmpnode->addr, &tmpdata, sizeof(struct sockaddr_in)) == 0){ptmpnode->ppre->pnext = ptmpnode->pnext;if(ptmpnode->pnext != NULL){ptmpnode->pnext->ppre = ptmpnode->ppre;}pfreenode = ptmpnode;ptmpnode = ptmpnode->pnext;free(pfreenode);} else {ptmpnode = ptmpnode->pnext;}}return 0;
}

3.UDP连接需要的头文件

#ifndef _HEAD_H_
#define _HEAD_H_#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<pthread.h>
#include<sys/types.h>
#include<sys/socket.h>
#include<signal.h>
#include<sys/wait.h>
#include<fcntl.h>
#include<errno.h>
#include<time.h>
#include<netinet/in.h>enum MSG_TYPE{LOGIN,CHAT,QUIT,
};typedef struct msg{enum MSG_TYPE type;char name[20];char text[1024];uint32_t ip;
}msg_t;#endif

4.客户端

#include"head.h"
msg_t msg;int clifd;
struct sockaddr_in seraddr;
socklen_t len = sizeof(seraddr);int sendto_ser(msg_t *pmsg){sendto(clifd,pmsg,sizeof(msg_t),0,(const struct sockaddr*)&seraddr,len);return 0;
}void *thread1(void* arg){while(1){if(msg.type == CHAT){memset(msg.text,0,1024);fgets(msg.text,1024,stdin);msg.text[strlen(msg.text)-1] = '\0';if(strncmp(msg.text,"quit",4) == 0){msg.type = QUIT;sendto_ser(&msg);exit(0);}sendto_ser(&msg);}}return NULL;
}
void *thread2(void* arg){msg_t msg;while(recvfrom(clifd,&msg,sizeof(msg),0,(struct sockaddr*)&seraddr,&len)>0){printf("%s :%s\n",msg.name,msg.text);}return NULL;
}int main(void){pthread_t pid1;pthread_t pid2;clifd = socket(AF_INET,SOCK_DGRAM,0);if(clifd < 0){perror("fail to socket");return -1;}memset(&seraddr,0,sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50426);seraddr.sin_addr.s_addr = inet_addr("127.0.0.1");msg.type = LOGIN;memset(msg.text,0,1024);msg.ip = seraddr.sin_addr.s_addr;printf("please input your name:");fgets(msg.name,20,stdin);msg.name[strlen(msg.name)-1] = '\0';sendto_ser(&msg);msg.type = CHAT;void *(*p1)(void*) = thread1;void *(*p2)(void*) = thread2;pthread_create(&pid1,NULL,p1,NULL);pthread_create(&pid2,NULL,p2,NULL);pthread_join(pid1,NULL);pthread_join(pid2,NULL);return 0;
}

5.服务器

#include"head.h"
#include"doublelist.h"int serfd;
struct sockaddr_in seraddr;struct sockaddr_in cliaddr;
socklen_t len = sizeof(cliaddr);int main(void){serfd = socket(AF_INET,SOCK_DGRAM,0);if(serfd < 0){perror("fail to socket");return -1;}memset(&seraddr,0,sizeof(seraddr));seraddr.sin_family = AF_INET;seraddr.sin_port = htons(50426);seraddr.sin_addr.s_addr = INADDR_ANY;if(bind(serfd,(const struct sockaddr*)&seraddr,sizeof(seraddr))<0){perror("fail to bind");return -1;}linknode *clilist = NULL;clilist = create_empty_linklist();if(clilist == NULL){return -1;}msg_t msg;while(1){memset(&msg,0,sizeof(msg));recvfrom(serfd,&msg,sizeof(msg),0,(struct sockaddr*)&cliaddr,&len);msg.ip = cliaddr.sin_addr.s_addr;if(msg.type == LOGIN){if(find_linklist(clilist,cliaddr) == NULL){insert_head_linklist(clilist,cliaddr);show_hi_linklist(clilist,&msg,serfd);}}else if(msg.type == CHAT){send_linklist(clilist,&msg,serfd);}else if(msg.type == QUIT){delete_linklist(clilist,cliaddr);show_bye_linklist(clilist,&msg,serfd);}}return 0;
}
http://www.dtcms.com/a/347574.html

相关文章:

  • 神经网络|(十三)概率论基础知识-贝叶斯公式和全概率公式
  • More Effective C++ 条款04:非必要不提供默认构造函数
  • c++string
  • 【计算机网络 | 第8篇】编码与调制
  • 青少年机器人技术(二级)等级考试试卷-实操题(2024年9月)
  • 笔试——Day47
  • 张老师---个人师资介绍
  • python学习DAY49打卡
  • 智慧矿山误报率↓83%!陌讯多模态融合算法在矿用设备监控的落地优化
  • 鸿蒙中CPU活动分析:CPU分析
  • 周末总结(2024/08/23)
  • 数组拆分求最大不重复数和(动态规划解法)
  • Linux内核进程管理子系统有什么第三十三回 —— 进程主结构详解(29)
  • java猜数字游戏(赌城主题版)
  • 注意力机制:捕获长距离依赖关系的革命性技术
  • mysqlbinlog解析命令
  • 订单号老是撞车?我写了个通用 PHP ID 生成器
  • linux添加新硬盘挂载分区和数据迁移
  • 云计算之云主机Linux是什么?有何配置?如何选?
  • Agent原理、构建模式(附视频链接)
  • Python打卡Day50 预训练模型+CBAM模块
  • 【Camera驱动】GMS测试项中Camera FOV Calibration问题详解
  • ROS机器人运动控制
  • 布偶猫吃什么猫粮比较好?2025猫粮品牌排名
  • 如何创建自己的 Minecraft 世界
  • 8月23号打卡
  • MySql知识梳理之DML语句
  • FL Studio Win版.exe安装教程(直接安装版/详细步骤/附安装包下载)
  • 基于STM32的病房监测系统/环境监测系统/人体健康监测系统
  • 曲面方程的三维可视化:从数学解析到Python实现