基于(LinuxC语言)的UDP局域网聊天室
生活随笔
收集整理的這篇文章主要介紹了
基于(LinuxC语言)的UDP局域网聊天室
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
功能:
? ? ? ? 1)用戶登錄提示.
? ? ? ??
? ? ? ? 2)服務器轉發客戶端發來的消息給其他客戶端.
? ? ? ??
? ? ? ? 3)當前客戶端輸入quit可以退出自己,并且服務器轉發退出提示.
??
? ? ? ? 4)服務器會轉發自己從終端輸入的內容給所有客戶端.
注意:
????????1)服務器端需要命令行傳參的方式輸入端口號.
????????2)客戶端需要命令行傳參的方式輸入ip地址以及端口號.
????????3)因為我懶并未設置 “客戶端ctrl+c”等信號 退出客戶會轉發用戶退出的功能(你想的話可以在服務器端signal接收下信號,并設置處理方式).
????????4)本程序用“fork函數”以多進程的方式實現多路復用,請注意.
????????5)本聊天室僅限于同一網段內進行通信.
? ? ? ? 6)因為我是一個人測試的,所以重復我是根據端口號來判斷的,后面因為懶又不想改了,你們可以改為姓名判斷或者是ip判斷的.
代碼:
? ? ? ? ?注:本人較懶,所以注釋有點少
服務器端:
? ? ??
#include<stdio.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <unistd.h> #include<stdlib.h> typedef struct {char name[32]; char text[256]; }MSG; typedef struct sockadd {struct sockaddr_in data;struct sockadd *next; }sock_t;/***************************注意,接收的消息第一個字符代表類型,‘n’為名字,代表用戶登錄‘t’為消息,代表是用戶發的消息*///創建表頭 sock_t *cret_sockadd(void) {sock_t *p=(sock_t *)malloc(sizeof(sock_t));if(NULL==p){perror("sockadd err.");return NULL;}p->next=NULL;return p; }//用戶退出刪除用戶 void del_sock(sock_t *p,int sockfd,struct sockaddr_in a,char msg[]) {char buf[32]="",quit[]="quit";strncpy(buf,msg+1,1);strcat(buf," sir exit chat.");sock_t *pdel=NULL;sock_t *pt=NULL;sock_t *q=p;while(p->next!=NULL){pt=p;p=p->next;if(p->data.sin_port==a.sin_port){sendto(sockfd,quit,sizeof(quit),0,(struct sockaddr *)&p->data,sizeof(p->data));pdel=p;pt->next=pdel->next;free(pdel);pdel=NULL;puts(buf);while(q->next!=NULL){q=q->next;sendto(sockfd,buf,sizeof(buf),0,(struct sockaddr *)&(q->data),sizeof(q->data));}}} }//添加用戶 int add_sock(sock_t *p,struct sockaddr_in a) {while(p->next!=NULL)p=p->next;sock_t *pnew=(sock_t *)malloc(sizeof(sock_t));if(NULL==pnew){perror("pnew malloc err.");return -1;}pnew->data=a;pnew->next=p->next;p->next=pnew;return 0; }int main(int argc, const char *argv[]) {int i;sock_t *p=cret_sockadd();MSG msg;int sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("socket err.");return -1;}struct sockaddr_in servcr;servcr.sin_family=AF_INET;servcr.sin_port=htons(atoi(argv[1]));servcr.sin_addr.s_addr=htonl(INADDR_ANY);struct sockaddr_in clint;socklen_t len=sizeof(clint);char buf[32];if(bind(sockfd,(struct sockaddr *)&servcr,sizeof(servcr))<0){perror("bind err.");return -1;}pid_t pid=fork();if(pid<0){perror("fork err.");return -1;}else if(pid==0) //子進程,自己發消息給父進程,然后父進程轉發消息給客戶{char temp[256]="";while(1){bzero(temp,sizeof(temp));bzero(buf,sizeof(buf));fgets(buf,32,stdin);if(buf[strlen(buf)-1]=='\n')buf[(strlen(buf)-1)]='\0';strcat(temp,"tFuWuqi say:");strcat(temp,buf);sendto(sockfd,temp,sizeof(temp),0,(struct sockaddr *)&servcr,sizeof(servcr));}}else{while(1){bzero(&msg,sizeof(msg));recvfrom(sockfd,msg.text,sizeof(msg.text),0,(struct sockaddr *)&clint,&len);if(strcmp(&(msg.text[strlen(msg.text)-4]),"quit")==0){del_sock(p,sockfd,clint,msg.text);continue;}if(msg.text[0]=='n') //接收的消息第一個字符如果是n代表用戶登錄{add_sock(p,clint); sock_t *q=p;printf("%s login\n",msg.text+1);printf("=================\n");strcat(msg.text," login");while(q->next!=NULL){q=q->next;if(q->data.sin_port==clint.sin_port)//不給自己發消息continue;sendto(sockfd,msg.text+1,sizeof(msg.text),0,(struct sockaddr *)&(q->data),sizeof(q->data));}q=NULL;continue;//跳過服務器打印消息}else if(msg.text[0]=='t')//如果是t,代表是消息{sock_t *x=p;while(x->next!=NULL)//轉發給其他用戶{x=x->next;if(x->data.sin_port==clint.sin_port)//跳過自己continue;sendto(sockfd,msg.text+1,sizeof(msg.text),0,(struct sockaddr *)&(x->data),sizeof(x->data));}x=NULL;}printf("%s\n",(msg.text+1)); //服務器打印消息 printf("=================\n");}wait(NULL);}free(p);p=NULL;close(sockfd);return 0; }?客戶端:
???
#include<stdio.h> #include<string.h> #include<sys/types.h> #include<sys/socket.h> #include <netinet/in.h> #include <netinet/ip.h> #include <unistd.h>#include <stdlib.h> typedef struct {char name[32];char text[256]; }MSG;int main(int argc, const char *argv[]) {int sockfd=socket(AF_INET,SOCK_DGRAM,0);if(sockfd<0){perror("socket err.");return -1;}struct sockaddr_in servcr;servcr.sin_family=AF_INET;servcr.sin_port=htons(atoi(argv[2]));servcr.sin_addr.s_addr=inet_addr(argv[1]);socklen_t len=sizeof(servcr);MSG msg;int s=0;char buf[128]="";msg.name[0]='n'; //把發送的消息第一位賦值‘n’,代表是用戶登錄printf("please input your name:");fgets(msg.name+1,31,stdin); //發消息的第一位變為標志位,所以從第二位開始輸入if(msg.name[strlen(msg.name)-1]=='\n') //因為fgets會多一個‘\n’,把其覆蓋掉msg.name[(strlen(msg.name)-1)]='\0';int a=sendto(sockfd,msg.name,32,0,(struct sockaddr *)&servcr,sizeof(servcr));//發送登錄用戶名strcat(msg.name," say:"); //名字與say拼接起來pid_t pid=fork();if(pid<0){perror("fork err.");return -1;}else if(pid==0){while(1){if(s==1) //如果用戶退出會把s置1表示用戶退出,這時候結束子進程break;bzero(msg.text,sizeof(msg.text));bzero(buf,sizeof(buf));msg.name[0]='t'; //把標志位為‘t’,代表發送的是消息,會覆蓋掉‘n’或者‘t’,消息不受影響printf("Please input:");fflush(NULL);fgets(buf,sizeof(msg.text),stdin);if(buf[strlen(buf)-1]=='\n')buf[(strlen(buf)-1)]='\0';if(strcmp(buf,"quit")==0)s=1;strcat(msg.text,msg.name);//把xx說與發送的消息拼接起來strcat(msg.text,buf); //發送quit,服務器收到會刪除用戶sendto(sockfd,msg.text,256,0,(struct sockaddr *)&servcr,sizeof(servcr));}exit(0);}else{while(1){bzero(msg.text,sizeof(msg.text));recvfrom(sockfd,msg.text,sizeof(msg.text),0,(struct sockaddr *)&servcr,&len);puts("");puts("=================");if(strcmp(msg.text,"quit")==0) //子進程結束后會跳出,父進程會接收到quit,然后退出進程break;printf("%s\n",msg.text);puts("=================");}wait(NULL);}close(sockfd);return 0; }?????
?emmm,有很多方面我做的并不是很好,還有其他解決方法,你可以使用別樣的方法完成,如果這里有啥做的不對的,歡迎各位大佬幫忙指正,小白在這里感謝,最后,讓我們一起加油,一起努力,未來可期!
總結
以上是生活随笔為你收集整理的基于(LinuxC语言)的UDP局域网聊天室的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Unity设置天空盒子
- 下一篇: linux 其他常用命令