当前位置: 首页> 游戏> 手游 > 嵌入式学习

嵌入式学习

时间:2025/7/10 13:33:01来源:https://blog.csdn.net/qq_46068832/article/details/139223346 浏览次数:0次

基于UDP的网络聊天室

        流程图。(注意:这里服务器和客户端运行的时候都需要在终端后面紧跟着IP和端口号。)

         服务器代码。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <poll.h>
#include <errno.h>
#include <sqlite3.h>/*
#define SER_PORT 8888
#define SER_IP "192.168.125.122"
*/typedef struct msg {char code;//操作码   'L'登录   'C'群聊   'Q'退出char name[20];char txt[128];
}msg_t;typedef struct node_cin {struct sockaddr_in c_addr;struct node_cin *next;
}node_t;//创建结点
int creat_node(node_t **p);
//登录
int do_login(struct sockaddr_in cin,node_t *phead,int sfd,msg_t msg);
//群聊
int do_chat(struct sockaddr_in cin,node_t *phead,int sfd,msg_t msg);
//退出
int do_quit(struct sockaddr_in cin,node_t *phead,int sfd,msg_t msg);int main(int argc, const char *argv[])
{//创建套接字,UDP通信int sfd=socket(AF_INET,SOCK_DGRAM,0);if(-1 == sfd){perror("socket error");return -1;}//printf("socket success\n");//绑定IP地址和端口号//准备填充地址结构体信息struct sockaddr_in sin;sin.sin_family=AF_INET;//sin.sin_port=htons(SER_PORT);sin.sin_port=htons(atoi(argv[2]));//sin.sin_addr.s_addr=inet_addr(SER_IP);sin.sin_addr.s_addr=inet_addr(argv[1]);socklen_t sin_len=sizeof(sin);//绑定工作if(bind(sfd,(struct sockaddr*)&sin,sizeof(sin)) == -1){perror("bind error");return -1;}//printf("bind success\n");//保存客户端网络信息的结构体struct sockaddr_in cin;socklen_t cin_len=sizeof(cin);msg_t msg;pid_t pid=fork();if(pid>0){//父进程发送系统消息//服务器发系统消息时,把父进程当做一个客户端,以群聊的方式向子进程发送系统消息msg.code='C';strcpy(msg.name,"server");while(1){fgets(msg.txt,128,stdin);msg.txt[strlen(msg.txt)-1]='\0';if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&sin,sin_len) == -1){perror("sendto error");}}}else if(0 == pid){//子进程用来接收并处理数据node_t *phead=NULL;creat_node(&phead);phead->next=NULL;while(1){memset(&msg,0,sizeof(msg));memset(&cin,0,sizeof(cin));if(recvfrom(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,&cin_len) == -1){perror("recvfrom error");return -1;}printf("%s发来消息-->%s\n",msg.name,msg.txt);switch(msg.code){case 'L'://cin是收到的客户端的网络信息结构体//phead是链表的头结点//sfd是转发消息的套接字//msg是要转发给所有用户的数据do_login(cin,phead,sfd,msg);break;case 'C':do_chat(cin,phead,sfd,msg);break;case 'Q':do_quit(cin,phead,sfd,msg);break;}}}else {perror("fork error");return -1;}close(sfd);return 0;
}//创建链表结点
int creat_node(node_t **p)
{*p=(node_t*)malloc(sizeof(node_t));
}//登录
int do_login(struct sockaddr_in cin,node_t *phead,int sfd,msg_t msg)
{//先遍历链表 将 xxx登录 的消息发送给所有人node_t *ptemp=phead;while(ptemp->next != NULL){ptemp=ptemp->next;if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(ptemp->c_addr),sizeof(ptemp->c_addr)) == -1){perror("sendto error");return -1;}}//将新登录的用户头插到链表中node_t *pnew=NULL;creat_node(&pnew);pnew->c_addr=cin;pnew->next=phead->next;phead->next=pnew;return 0;
}//群聊
int do_chat(struct sockaddr_in cin,node_t *phead,int sfd,msg_t msg)
{//群聊。服务器只需要转发//遍历链表,将群聊的消息发送给除了自己之外的所有人node_t *ptemp=phead;while(ptemp->next != NULL){ptemp=ptemp->next;if(memcmp(&cin,&(ptemp->c_addr),sizeof(cin))){if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(ptemp->c_addr),sizeof(ptemp->c_addr)) == -1){perror("sendto error");return -1;}}}
}//退出
int do_quit(struct sockaddr_in cin,node_t *phead,int sfd,msg_t msg)
{//把要退出的客户端从链表中删除,并且把退出的消息转发给其他所有人node_t *ptemp=phead;while(ptemp->next != NULL){if(memcmp(&cin,&(ptemp->next->c_addr),sizeof(cin))){//不是自己,就发送数据ptemp=ptemp->next;if(sendto(sfd,&msg,sizeof(msg),0,(struct sockaddr*)&(ptemp->c_addr),sizeof(ptemp->c_addr)) == -1){perror("sendto error");return -1;}}else {//如果是自己,就将自己在链表中删除node_t *pdel=ptemp->next;ptemp->next=pdel->next;free(pdel);pdel=NULL;}}
}

         客户端代码。

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <pthread.h>
#include <semaphore.h>
#include <wait.h>
#include <signal.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <semaphore.h>
#include <sys/msg.h>
#include <sys/shm.h>
#include <sys/un.h>
#include <poll.h>
#include <errno.h>
#include <sqlite3.h>typedef struct msg {char code;//操作码   'L'登录   'C'群聊   'Q'退出char name[20];char txt[128];
}msg_t;int main(int argc, const char *argv[])
{//创建套接字int cfd=socket(AF_INET,SOCK_DGRAM,0);if(-1 == cfd){perror("socket error");return -1;}printf("socket success\n");//准备填充地址结构体信息struct sockaddr_in cin;cin.sin_family=AF_INET;cin.sin_port=htons(atoi(argv[2]));cin.sin_addr.s_addr=inet_addr(argv[1]);socklen_t cin_len=sizeof(cin);msg_t msg;memset(&msg,0,sizeof(msg));printf("请输入用户名:");fgets(msg.name,20,stdin);msg.name[strlen(msg.name)-1]='\0';                                       //给服务器发送登录的数据包msg.code='L';strcpy(msg.txt,"加入群聊");if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,cin_len) == -1){perror("sendto error");return -1;}pid_t pid=fork();if(pid>0){//父进程发送数据while(1){msg.code='C';//先默认一开始的时候都是群聊fgets(msg.txt,128,stdin);msg.txt[strlen(msg.txt)-1]='\0';//判断是否是退出if(!strcmp(msg.txt,"quit")){msg.code='Q';strcpy(msg.txt,"退出群聊");}if(sendto(cfd,&msg,sizeof(msg),0,(struct sockaddr*)&cin,cin_len) == -1){perror("sendto error");return -1;}if(!strcmp(msg.txt,"退出群聊")){break;}}//父进程结束前,先杀死子进程kill(pid,SIGKILL);wait(NULL);close(cfd);}else if(0 == pid){//子进程接收服务器发来的数据并打印while(1){memset(&msg,0,sizeof(msg));if(recvfrom(cfd,&msg,sizeof(msg),0,NULL,NULL) == -1){perror("recvfrom error");return -1;}printf("%s发来消息-->%s\n",msg.name,msg.txt);}}else {perror("fork error");return -1;}return 0;
}

关键字:嵌入式学习

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: