学习嵌入式第三十六天
文章目录
- 网络聊天室
- 1.实现原理
- 2.实现步骤
- 1.客户端
- 1.客户端1需要处理的情况
- 2.客户端...需要处理的情况
- 2.服务器
- 3.需要用到的一些知识
- 1.链表
- 2.结构体和枚举
- 3.具体实现
- 1.链表所依赖的头文件
- 2.链表用到的相关的函数
- 3.UDP连接需要的头文件
- 4.客户端
- 5.服务器
网络聊天室
1.实现原理
- 服务器通过UDP协议将接入的客户端汇总起来,并将消息转发出去
- 客户端分别有聊天,下线以及登录三个状态
2.实现步骤
1.客户端
1.客户端1需要处理的情况
- 客户端与服务器端建立连接
- 向服务器发送消息
- 当有其余客户端接入聊天室,需要接收其余客户端发来的消息
- 客户端与服务器断开连接
2.客户端…需要处理的情况
- 客户端与服务器建立连接
- 向服务器发送消息
- 接收其余客户端发来的消息
- 客户端与服务器端断开连接
2.服务器
- 服务器接收到客户端上线的消息并将其保存,将这个客户端上线的消息转发给所有的客户端
- 服务器接收客户端发来的消息,并将这个消息转发给所有客户端
- 服务器接收客户端下线的消息,并将这个客户端下线的消息转发给其余的客户端
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;
}