基于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 }

 

posted @ 2021-05-29 23:21  熊猫耳朵  阅读(1913)  评论(2编辑  收藏  举报