C語言利用UDP實現(xiàn)群聊聊天室的示例代碼
1.UDP群聊的功能
有新用戶登錄,其他在線的用戶可以收到登錄信息
有用戶群聊,其他在線的用戶可以收到群聊信息
有用戶退出,其他在線的用戶可以收到退出信息
服務(wù)器可以發(fā)送系統(tǒng)信息
2.寫項目的流程
畫流程圖
根據(jù)流程圖寫框架
一個功能一個功能實現(xiàn)
3.流程圖
4.代碼實現(xiàn)
4.1頭文件
#ifndef __MYHEAD_H__ #define __MYHEAD_H__ #include <head.h> #define N 512 //聊天操作用的結(jié)構(gòu)體 typedef struct _MSG{ char ch;//用來'l'聊天,'q'退出,'登錄d' char name[128];//存名字 char text[N];//存聊天內(nèi)容 }msg_t; //用來保存每個用戶信息的結(jié)構(gòu)體 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函數(shù)
#include "myhead.h" //創(chuàng)建一個單鏈表頭 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; } //將這個用戶登錄的信息發(fā)送給所有人 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("將用戶登錄信息發(fā)給所有人失敗"); } } //創(chuàng)建一個新的節(jié)點,并且把新的用戶信息放入新得單列表 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; } //將接受到的消息發(fā)給除了自己以外的所有人 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("將聊天內(nèi)容發(fā)給所有人失敗"); } } } 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服務(wù)器
#include "myhead.h" int main(int argc, char const *argv[]) { int sockfd=0; pid_t pid=0; msg_t msg;//用來進(jìn)行各種操作 msg_t faso;//用來發(fā)系統(tǒng)消息 if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){ ERRLOG("創(chuàng)建服務(wù)器套接字失敗"); } //將網(wǎng)絡(luò)信息結(jié)構(gòu)體放入服務(wù)器中 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); //將套接字與網(wǎng)絡(luò)信息結(jié)構(gòu)體綁定 if(bind(sockfd,(struct sockaddr*)&serveraddr,serveraddr_len)==-1){ ERRLOG("將套接字與網(wǎng)絡(luò)信息結(jié)構(gòu)體綁定失敗"); } //創(chuàng)建一個新的網(wǎng)絡(luò)信息結(jié)構(gòu)體來存客戶端的信息 struct sockaddr_in clientaddr; clientaddr.sin_family=AF_INET; socklen_t clientaddr_len=sizeof(clientaddr); //創(chuàng)建進(jìn)程 pid=fork(); if(pid==-1){ ERRLOG("服務(wù)器創(chuàng)建進(jìn)程失敗"); }else if(pid==0){ //創(chuàng)建一個單列表保存網(wǎng)絡(luò)信息結(jié)構(gòu)體 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){ //發(fā)系統(tǒng)消息 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","系統(tǒng)消息"); if(sendto(sockfd,&faso,sizeof(faso),0,(struct sockaddr*)&serveraddr,serveraddr_len)==-1){ ERRLOG("發(fā)送系統(tǒng)消息失敗"); } } } 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;//創(chuàng)建發(fā)送用戶的信息 if((sockfd=socket(AF_INET,SOCK_DGRAM,0))==-1){ ERRLOG("創(chuàng)建客戶端套接字失敗"); } //將客戶端網(wǎng)絡(luò)信息結(jié)構(gòu)體進(jìn)行綁定 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); //輸入用戶的姓名進(jìn)行登錄操作 msg.ch='d'; printf("請輸入你用來登錄的姓名"); fgets(msg.name,sizeof(msg.name),stdin); msg.name[strlen(msg.name)-1]='\0'; //給服務(wù)器發(fā)送用戶已經(jīng)登錄上的操作 if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,clientaddr_len)==-1){ ERRLOG("客戶端給服務(wù)器發(fā)送的登錄信息失敗"); } //創(chuàng)建進(jìn)程,子進(jìn)程用來接受,父進(jìn)程用來發(fā)送 pid=fork(); if(pid==-1){ ERRLOG("客戶端創(chuàng)建進(jìn)程失敗"); }else if(pid==0){ //用來接受服務(wù)器發(fā)來的消息 while(1){ memset(&msg,0,sizeof(msg)); if(recvfrom(sockfd,&msg,sizeof(msg),0,NULL,NULL)==-1){ ERRLOG("接受服務(wù)器發(fā)來的信息錯誤"); } printf("[%s]>>(%s)\n",msg.name,msg.text); } }else{ //寫入要判聊天的內(nèi)容 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'; } //將寫好的內(nèi)容發(fā)送給服務(wù)器 if(sendto(sockfd,&msg,sizeof(msg),0,(struct sockaddr*)&clientaddr,clientaddr_len)==-1){ ERRLOG("將聊天內(nèi)容發(fā)送給服務(wù)器失敗"); } //當(dāng)識別到停止的時候,關(guān)閉進(jìn)程 if(strncmp("quit",msg.text,5)==0){ kill(pid,SIGKILL); close(sockfd); exit(EXIT_SUCCESS); } } } return 0; }
到此這篇關(guān)于C語言利用UDP實現(xiàn)群聊聊天室的示例代碼的文章就介紹到這了,更多相關(guān)C語言 UDP聊天室內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言輪轉(zhuǎn)數(shù)組的三種實現(xiàn)
輪轉(zhuǎn)數(shù)組是一種將數(shù)組元素循環(huán)移動的處理方式,它通常用于解決一些需要對固定長度的數(shù)組進(jìn)行循環(huán)滾動處理的問題,本文就介紹了C語言輪轉(zhuǎn)數(shù)組的三種實現(xiàn),感興趣的可以了解一下2023-08-08

c語言實現(xiàn)把文件中數(shù)據(jù)讀取并存到數(shù)組中

Cocos2d-x學(xué)習(xí)筆記之Hello World源碼分析