C語言利用UDP實現群聊聊天室的示例代碼
1.UDP群聊的功能
有新用戶登錄,其他在線的用戶可以收到登錄信息
有用戶群聊,其他在線的用戶可以收到群聊信息
有用戶退出,其他在線的用戶可以收到退出信息
服務器可以發送系統信息
2.寫項目的流程
畫流程圖
根據流程圖寫框架
一個功能一個功能實現
3.流程圖
4.代碼實現
4.1頭文件
#ifndef __MYHEAD_H__ #define __MYHEAD_H__ #include <head.h> #define N 512 //聊天操作用的結構體 typedef struct _MSG{ char ch;//用來'l'聊天,'q'退出,'登錄d' char name[128];//存名字 char text[N];//存聊天內容 }msg_t; //用來保存每個用戶信息的結構體 typedef struct _Jilu{ struct sockaddr_in addr; struct _Jilu *next; }jilu_t; int create_head(jilu_t **head); int input_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len); int wx_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len); int tuichu_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len); #endif
4.2函數
#include "myhead.h" //創建一個單鏈表頭 int create_head(jilu_t **head) { if(head==NULL){ printf("傳送錯誤,請檢查\n"); return -1; } (*head)=(jilu_t *)malloc(sizeof(jilu_t)); (*head)->next=NULL; return 0; } //記錄登錄的用戶的信息 int input_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len) { if(head==NULL){ printf("傳送錯誤,請檢查\n"); return -1; } //將這個用戶登錄的信息發送給所有人 snprintf(msg.text,sizeof(msg.text),"[%s]%s",msg.name,"登錄瞭"); //這個用來記錄頭的地址 jilu_t *jilu_head=head; while(jilu_head->next!=NULL){ jilu_head=jilu_head->next; if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&jilu_head->addr,clientaddr_len)==-1){ ERRLOG("將用戶登錄信息發給所有人失敗"); } } //創建一個新的節點,並且把新的用戶信息放入新得單列表 jilu_t *temp=NULL; create_head(&temp); temp->addr=clientaddr; //用頭插法將用戶信息插入鏈表 temp->next=head->next; head->next=temp; return 0; } int wx_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len) { if(head==NULL){ printf("傳送錯誤,請檢查\n"); return -1; } //將接受到的消息發給除瞭自己以外的所有人 jilu_t *jilu_head=head; while(jilu_head->next!=NULL){ jilu_head=jilu_head->next; if(0!=memcmp(&(jilu_head->addr),&clientaddr,sizeof(clientaddr))){ if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&jilu_head->addr,clientaddr_len)==-1){ ERRLOG("將聊天內容發給所有人失敗"); } } } return 0; } int tuichu_addr(jilu_t *head,msg_t msg,int sockfd,struct sockaddr_in clientaddr,socklen_t clientaddr_len) { if(head==NULL){ printf("傳送錯誤,請檢查\n"); return -1; } snprintf(msg.text,sizeof(msg.text),"%s%s",msg.name,"退出登錄"); jilu_t *jilu_head=head; jilu_t *pdel=NULL; while(jilu_head->next!=NULL){ if(0==memcmp(&(jilu_head->next->addr),&clientaddr,sizeof(clientaddr))){ pdel=jilu_head->next; jilu_head->next=pdel->next; free(pdel); pdel=NULL; }else{ jilu_head=jilu_head->next; if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&jilu_head->addr,clientaddr_len)==-1){ ERRLOG("將這個退出的信息告訴所有人失敗"); } } } return 0; }
4.3服務器
#include "myhead.h" int main(int argc, char const *argv[]) { int sockfd=0; pid_t pid=0; msg_t msg;//用來進行各種操作 msg_t faso;//用來發系統消息 if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){ ERRLOG("創建服務器套接字失敗"); } //將網絡信息結構體放入服務器中 struct sockaddr_in serveraddr; memset(&serveraddr,0,sizeof(serveraddr)); serveraddr.sin_family=AF_INET; serveraddr.sin_port=htons(atoi(argv[2])); serveraddr.sin_addr.s_addr=inet_addr(argv[1]); socklen_t serveraddr_len=sizeof(serveraddr); //將套接字與網絡信息結構體綁定 if(bind(sockfd,(struct sockaddr*)&serveraddr,serveraddr_len)==-1){ ERRLOG("將套接字與網絡信息結構體綁定失敗"); } //創建一個新的網絡信息結構體來存客戶端的信息 struct sockaddr_in clientaddr; clientaddr.sin_family=AF_INET; socklen_t clientaddr_len=sizeof(clientaddr); //創建進程 pid=fork(); if(pid==-1){ ERRLOG("服務器創建進程失敗"); }else if(pid==0){ //創建一個單列表保存網絡信息結構體 jilu_t *head; create_head(&head); memset(&msg,0,sizeof(msg)); while(1){ if(recvfrom(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,&clientaddr_len)==-1){ ERRLOG("接受客戶端傳來的信息失敗"); } switch(msg.ch){ case 'd'://登錄信息 input_addr(head,msg,sockfd,clientaddr,clientaddr_len); //head->next=NULL; //這個用來測試用的 break; case 'l'://聊天信息 wx_addr(head,msg,sockfd,clientaddr,clientaddr_len); break; case 'q'://退出信息 tuichu_addr(head,msg,sockfd,clientaddr,clientaddr_len); break; } } }else{ while(1){ //發系統消息 memset(&faso,0,sizeof(faso)); fgets(faso.text,sizeof(faso.text),stdin); faso.text[strlen(faso.text)-1]='\0'; faso.ch='l'; sprintf(faso.name,"%s","系統消息"); if(sendto(sockfd,&faso,sizeof(faso),0,(struct sockaddr*)&serveraddr,serveraddr_len)==-1){ ERRLOG("發送系統消息失敗"); } } } return 0; }
4.4客戶端
#include "myhead.h" int main(int argc, char const *argv[]) { //判斷輸入的對不對 if(argc!=3){ printf("輸入格式錯誤,./a.out ip port\n"); exit(EXIT_SUCCESS); } int sockfd=0; pid_t pid=0; msg_t msg;//創建發送用戶的信息 if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){ ERRLOG("創建客戶端套接字失敗"); } //將客戶端網絡信息結構體進行綁定 struct sockaddr_in clientaddr; memset(&clientaddr,0,sizeof(clientaddr)); clientaddr.sin_family=AF_INET; clientaddr.sin_port=htons(atoi(argv[2])); clientaddr.sin_addr.s_addr=inet_addr(argv[1]); socklen_t clientaddr_len=sizeof(clientaddr); //輸入用戶的姓名進行登錄操作 msg.ch='d'; printf("請輸入你用來登錄的姓名"); fgets(msg.name,sizeof(msg.name),stdin); msg.name[strlen(msg.name)-1]='\0'; //給服務器發送用戶已經登錄上的操作 if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,clientaddr_len)==-1){ ERRLOG("客戶端給服務器發送的登錄信息失敗"); } //創建進程,子進程用來接受,父進程用來發送 pid=fork(); if(pid==-1){ ERRLOG("客戶端創建進程失敗"); }else if(pid==0){ //用來接受服務器發來的消息 while(1){ memset(&msg,0,sizeof(msg)); if(recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL)==-1){ ERRLOG("接受服務器發來的信息錯誤"); } printf("[%s]>>(%s)\n",msg.name,msg.text); } }else{ //寫入要判聊天的內容 while(1){ memset(msg.text,0,sizeof(msg.text)); fgets(msg.text,sizeof(msg.text),stdin); msg.text[strlen(msg.text)-1]='\0'; if(strncmp("quit",msg.text,5)==0){ msg.ch='q'; }else{ msg.ch='l'; } //將寫好的內容發送給服務器 if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,clientaddr_len)==-1){ ERRLOG("將聊天內容發送給服務器失敗"); } //當識別到停止的時候,關閉進程 if(strncmp("quit",msg.text,5)==0){ kill(pid,SIGKILL); close(sockfd); exit(EXIT_SUCCESS); } } } return 0; }
到此這篇關於C語言利用UDP實現群聊聊天室的示例代碼的文章就介紹到這瞭,更多相關C語言 UDP聊天室內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!