基於Linux的TCP網絡聊天室


1.實驗項目名稱:基於Linux的TCP網絡聊天室

2.實驗目的:通過TCP完成多用戶群聊和私聊功能。

3.實驗過程:

         通過socket建立用戶連接並傳送用戶輸入的信息,分別來寫客戶端和服務器端,利用多線程來實現多用戶模式,服務器端隨時准備接收客戶端發送的消息,並判斷該消息類型(私聊或群聊)來進行對應的轉發工作,客戶端隨時接受來自服務器端的消息,從而實現消息的同步。

(1)開啟服務器。

 

(2)開啟客戶端,輸入用戶昵稱,客戶端開始與服務器建立連接。

 

(3)群聊功能,一名用戶發送消息,聊天室的其他成員均可收到此消息。

 

 

(4)私聊功能,一位用戶@其他用戶,則此消息只有被@的用戶可以收到。

 

 

用戶的信息借助結構體來存放,群聊功能通過遍歷結構體,把消息發送給每一名用戶,私聊功能通過對用戶所發消息進行判斷,若消息中存在@其他用戶則把該消息私發給指定用戶。

另外,私聊功能函數可以進行對各種@操作的判斷,如用戶所@的人不存在,則把此消息作為群消息發出,@其他用戶后沒有添加空格,則把此消息視為群發消息。

 

源碼:

頭文件

 1 //header.h
 2 #ifndef _A_H
 3 #define _A_H
 4 #include <stdio.h>
 5 #include <pthread.h>
 6 #include <sys/socket.h> 
 7 #include <netinet/in.h>
 8 #include <arpa/inet.h>
 9 #include <stdlib.h>
10 #include <unistd.h>
11 #include <string.h>
12 #include <signal.h>
13 #include <pthread.h>
14 struct client{
15     char name[30];    //客戶端名字 
16     int fds;        //客戶端socket描述符 
17 };
18 struct client c[100]={0};//接收客戶端100個 
19 int in;            //數組下標 
20 char *IP ="127.0.0.1"; //ip
21 short PORT=10222;
22 char NAME[20]={};    //@的名字 
23 int FLAG=0;        //標記是群發還是私聊 
24 #endif

服務器端

 1 //tcp_s.c
 2 #include "header.h"
 3 int sockfd;            //服務器socket 
 4 char tempName[20]={};
 5 //初始化服務器網絡
 6 void init(){
 7     printf("start chat room...");
 8     sockfd = socket(PF_INET,SOCK_STREAM,0);
 9     if(sockfd == -1){
10         perror("create socket false\n");
11         exit(-1);
12     }
13     struct sockaddr_in addr;    //網絡通信地址結構 
14     addr.sin_family = PF_INET;    //協議簇 
15     addr.sin_port = htons(PORT);    //端口
16     addr.sin_addr.s_addr = inet_addr(IP);    //IP地址
17     if(bind(sockfd,(struct sockaddr*)&addr,sizeof(addr)) == -1){
18         perror("bind false\n");
19         exit(-1);
20     } 
21     if(listen(sockfd,100) == -1){
22         perror("Setup listening failed\n");
23         exit(-1); 
24     }
25     printf("Server initialization succeeded!\n");
26 } 

分發消息

 1 void SendMessage(char *msg){
 2     int flag=0;        //標記@符號是否為私聊 
 3     int exit=0;        //比較@的用戶是否存在 
 4     int i=0,j=0;
 5     while(msg[i]!=':'){
 6         if(i>=strlen(msg))
 7             break;
 8         i++;
 9     }                        //找到@符號位置 
10     if(msg[i+1] == '@'){
11         i++;
12         while(msg[i]!=32){
13             if(i>=strlen(msg)){        //@符號不是私聊作用 
14                 flag=1;
15                 break;
16             }                
17             NAME[j]=msg[i+1];
18             i++;
19             j++;
20         }
21         if(flag){        //群發 
22             for(i=0;i<in;i++){
23                 printf("send to %d\n",c[i].fds);
24                 send(c[i].fds,msg,strlen(msg),0);
25             }        
26         }
27         else{            //私發 
28             for(i=0;i<in;i++){
29                 int k=0;
30                 for(k=0;k<strlen(NAME)-1;k++){
31                     tempName[k]=NAME[k];
32                 }                
33                 if(strcmp(c[i].name,tempName)==0){                
34                     send(c[i].fds,msg,strlen(msg),0);
35                     exit=1;  
36                     break;    
37                 }        
38             }
39         }
40     } 
41     else{ 
42         exit = 1;
43         for(i=0;i<in;i++){
44             printf("send to %d\n",c[i].fds);
45             send(c[i].fds,msg,strlen(msg),0);
46         }
47     }    
48     if(exit == 0){
49         for(i=0;i<in;i++){
50             printf("send to %d\n",c[i].fds);
51             send(c[i].fds,msg,strlen(msg),0);
52         }
53     }    
54 }

線程函數中進行通信/接收客戶端消息,分發給所有客戶端 

 1 void *server_thread(void *p){
 2     char name[30]={};
 3     if(recv(c[in].fds,name,sizeof(name),0)>0){
 4         name[strlen(name)]='\0';
 5         strcpy(c[in].name,name);
 6     }
 7     in++;
 8     char tip[100]={}; 
 9     sprintf(tip,"%s join in the chat room\n",c[in-1].name);
10     SendMessage(tip);
11     int fd = *(int*)p;
12     printf("pthread = %d\n",fd);
13     while(1){
14         char buf[100]={};
15         if(recv(fd,buf,sizeof(buf),0) == 0){
16             //表示退出連接 
17             printf("fd = %d left the chat room\n",fd);
18             int i,j;
19             char name[20]={};
20             int flag = 1;
21             for(i=0;i<in;i++){
22                 if(c[i].fds == fd){
23                     strcpy(name,c[i].name);
24                     i++;
25                     flag = 0;
26                 }
27                 if(flag != 1){
28                     c[i-1].fds = c[i].fds;
29                     strcpy(c[i-1].name,c[i].name);
30                 }
31             }
32             c[i].fds = 0;
33             strcpy(c[i].name,"");
34             in--;
35             char msg[100];
36             sprintf(msg,"%s left the chat room\n",name);
37             SendMessage(msg);
38             close(fd);
39             break;
40         }
41         SendMessage(buf); 
42     }
43 }

等待客戶端連接,啟動服務器的服務

 1 void server(){
 2     printf("Server starts service!\n");
 3     while(1){
 4         struct sockaddr_in fromaddr;    //存儲客戶端通信地址 
 5         socklen_t len = sizeof(fromaddr);
 6         int fd = accept(sockfd,(struct sockaddr*)&fromaddr,&len);
 7         if(fd == -1){
 8             perror("Client connection failed!\n");
 9             continue;            
10         }
11         c[in].fds = fd;
12         pthread_t pid;
13         pthread_create(&pid,0,server_thread,&fd);
14     }    
15 } 
16 void sig_close(){
17     close(sockfd);
18     printf("Server close\n");
19     exit(0);
20 }
21 int main()
22 {
23     signal(SIGINT,sig_close);
24     init();
25     server();
26     return 0;
27 }

客戶端

 1 //tcp_c.c
 2 #include "header.h" 
 3 char name[30];   //name
 4 int sockfd;        //客戶端socket 
 5 int mutax=0;    //互斥變量 
 6 void init(){
 7     printf("Client starts\n");
 8     sockfd =socket(PF_INET,SOCK_STREAM,0);
 9     struct sockaddr_in addr;
10     addr.sin_family =PF_INET;
11     addr.sin_port=htons(PORT);
12     addr.sin_addr.s_addr=inet_addr(IP);
13     if(connect(sockfd,(struct sockaddr*)&addr,sizeof (addr))==-1){
14         perror("connect failed\n");
15         exit(-1);
16     }
17 }  

通信

 1 void start(){
 2     pthread_t pid;
 3     void* receive_thread(void*);
 4     pthread_create(&pid,0,receive_thread,0);
 5     while(1){
 6         char buf[100]={};
 7         gets(buf); 
 8         char msg[100]={};
 9         if(mutax){
10             mutax=0;
11             continue;
12         }
13         sprintf(msg,"%s said:%s",name,buf);
14         send(sockfd,msg,strlen(msg),0);  
15 }
16 
17 }
18 void* receive_thread(void *p){
19     while(1){
20         char buf[100]={};
21         if(recv(sockfd,buf,sizeof(buf),0)<=0){
22             break;
23         }
24         printf("%s\n",buf);
25         }
26 }
27 void sig_close(){
28     close(sockfd);
29     exit(0);
30 }
31 int main(){
32     signal(SIGINT,sig_close);
33     printf("Please input your name:");
34     scanf("%s",name);
35     mutax=1;
36     init();
37     if(mutax)
38         send(sockfd,name,strlen(name),0);
39     start();
40     return 0;
41 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM