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

学习嵌入式第三十六天

文章目录

  • 网络聊天室
    • 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.xdnf.cn/news/18653.html

相关文章:

  • JAVA国际版东郊到家同城按摩服务美容美发私教到店服务系统源码支持Android+IOS+H5
  • PCB电路设计学习3 电路原理图设计 元件PCB封装设计与添加
  • Day12 数据统计-Excel报表
  • 数据结构——树状数组(Binary Indexed Tree)
  • UE5多人MOBA+GAS 53、测试专属服务器打包和连接,以及配置EOS
  • WiFi有网络但是电脑连不上网是怎么回事?该怎么解决?
  • 云原生高级——K8S总概
  • OpenHands:开源AI软件开发代理平台的革命性突破
  • 2025最新版mgg格式转MP3,mflac转mp3,mgg格式如何转mp3?
  • setup 语法糖核心要点
  • Windows应急响应一般思路(一)
  • MySQL 高级主题:索引优化、ORM 与数据库迁移
  • More Effective C++ 条款02:最好使用C++转型操作符
  • 【0基础PS】蒙版与剪贴蒙版详解
  • NoCode-bench:自然语言驱动功能添加的评估新基准
  • 3.4 缩略词抽取
  • 表格识别技术:通过图像处理与深度学习,将非结构化表格转化为可编辑结构化数据,推动智能化发展
  • Vue Teleport 原理解析与React Portal、 Fragment 组件
  • GEO优化专家孟庆涛发布:《GEO内容优化的四大黄金标准》
  • 普中烧录软件 PZISP,打不开,提示“应用程序无法启动,因为应用程序并行配置不正确.....”
  • 学习嵌入式第三十五天
  • Linux应用软件编程---网络编程1(目的、网络协议、网络配置、UDP编程流程)
  • APP Usage『安卓』:比系统自带强10倍!手机应用使用时长精确到秒
  • MySQL - 视图,事务和索引
  • java8 findAny()、findFirst()空指针NullPointerException问题
  • ​维基框架 (Wiki Framework) 1.1.0 版本发布​ 提供多模型AI辅助开发
  • 图像指针:高效处理像素数据的核心工具
  • Linux虚拟机安装FTP
  • AtCoder Beginner Contest 419(ABCDEF)
  • Python Flask快速实现163邮箱发送验证码