multi-threaded chat room
Service-Terminal:
Realize multi-user group chat function (the upper limit of the number of people can be set);
Messages sent by each user can be received by other users connected to the server;
The user enters "bye" to exit, and the server enters " quit " to exit.
There are three functions on the server
Main function main : server-side initialization, accepting connections;
Message processing function rcv_snd : Receive a message from a user, and send it to all other users after simple processing;
Exit function quit : When quit is entered , the server program terminates.
These three functions belong to three threads (to be precise, more than or equal to three). The Main function acts as the main thread and creates a thread where the exit function is located, and a thread that processes messages for this connection every time a new user is connected.
Client:
Establish a connection to the server, send and receive messages
The client has a total of two functions
Main function main : Initialize the client socket, establish a connection with the server, receive messages and display them locally
Send function snd : read the message from the console and send it to the server
These two functions run on two threads, one is the thread where the main function is located, and the other is the thread where the sending function created by the main function is located.
Attached:
Macro definition debug print switch
#define DEBUG_PRINT 1
#ifdef DEBUG_PRINT
#define DEBUG(format, ...) printf(“FILE: “__FILE__”, LINE: %d: “format”\n”, __LINE__, ##__VA_ARGS__)
#else
#define DEBUG(format, ...)
#endif
-lpthread is required when creating a thread when gcc compiles
Phtread_t thread; Pthread_creat(&thread, NULL, (void *)quit, NULL);
Pthread_creat(malloc(sizeof(pthread_t)), NULL, (void *)rcv_snd, (void *)i);
System time #include <time.h>
Time_t ticks = time(NULL); printf(“%s\n”, ctime(&ticks));
Server
Struct sockaddr_in serv_addr;
Bzero(&serv_addr, sizeof(serv_addr));
Serv_addr.sin_family = AF_INET;
Serv_addr.sin_port = htons(PORT);
Serv_addr.sin_addr.s_addr = htonl(INADDR_ANY);
Listenfd = socket (AF_INET, SOCK_STREAM, 0);
Bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
Listen(listenfd, 10);
Int len = sizeof(cli_addr);
Connfd[i] = accept(listenfd, (struct sockaddr *)&cli_addr, &len);
client
Struct sockaddr_in serv_addr;
Bzero(&serv_addr, sizeof(serv_addr));
Serv_addr.sin_family = AF_INET;
Serv_addr.sin_port = htons(PORT);
Inet_pton(IP, &serv_addr.sin_addr);
Sockfd = socket (AF_INET, SOCK_STREAM, 0);
Connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr));
source code server.c
1 #include <stdio.h> 2 #include <stdlib.h> // exit 3 #include <string.h> 4 #include <unistd.h> // bind listen 5 #include <time.h> // time(NULL) ctime(&ticks) 6 #include <netinet/in.h> 7 #include <arpa/inet.h> // must be included for inet_ntop 8 9 #define PORT 8000 10 #define MAXMEM 10 11 #define BUFFSIZE 128 12 13 //#define DEBUG_PRINT 1 // Macro definition debug switch 14 #ifdef DEBUG_PRINT 15 #define DEBUG(format, ...) printf("FILE: "__FILE__", LINE: %d: "format"\n", __LINE__, ##__VA_ARGS__) 16 #else 17 #define DEBUG(format, ...) 18 #endif 19 20 int listenfd, connfd[MAXMEM]; 21 22 void quit(); 23 void rcv_snd(int p); 24 25 int main() 26 { 27 struct sockaddr_in serv_addr, cli_addr; 28 // int len = sizeof(cli_addr), i; 29 int i; 30 time_t ticks; 31 pthread_t thread; 32 char buff[BUFFSIZE]; 33 34 printf("running...\n(Prompt: enter command ""quit"" to exit server)\n"); 35 DEBUG("=== initialize..."); // Initialize and fill the server address structure 36 bzero(&serv_addr, sizeof(struct sockaddr_in)); 37 serv_addr.sin_family = AF_INET; 38 serv_addr.sin_port = htons(PORT); 39 serv_addr.sin_addr.s_addr = htonl(INADDR_ANY); 40 41 DEBUG("=== socket..."); // socket creates a listening socket on the server side 42 listenfd = socket (AF_INET, SOCK_STREAM, 0); 43 if(listenfd < 0) 44 { 45 perror("fail to socket"); 46 exit(-1); 47 } 48 49 DEBUG("=== bind..."); // bind binds the socket to the populated address structure 50 if(bind(listenfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) 51 { 52 perror("fail to bind"); 53 exit(-2); 54 } 55 56 DEBUG("=== listening..."); // listen turns an actively connected socket into a passive listening socket 57 listen(listenfd, MAXMEM); 58 59 /* === Create a thread, manage the server program, and call the quit function === */ 60 pthread_create(&thread, NULL, (void *)(quit), NULL); 61 62 // Initialize the socket descriptor array to -1, indicating idle 63 for(i=0; i<MAXMEM; i++) 64 connfd[i] = -1; 65 66 while(1) 67 { 68 int len;// = sizeof(cli_addr); 69 for(i=0; i<MAXMEM; i++) 70 { 71 if(connfd[i] == -1) 72 break; 73 } 74 // accept gets a connection from the connection queue accepted by listen 75 connfd[i] = accept(listenfd, (struct sockaddr *)&cli_addr, &len); 76 if(connfd[i] < 0) 77 { 78 perror("fail to accept"); 79 // continue; // This sentence can be omitted, accept will block and wait 80 } 81 ticks = time(NULL); 82 //sprintf(buff, "%.24s\r\n", ctime(&ticks)); 83 printf("%.24s\n\tconnect from: %s, port %d\n", 84 ctime(&ticks), inet_ntop(AF_INET, &(cli_addr.sin_addr), buff, BUFFSIZE), 85 ntohs(cli_addr.sin_port)); // Note the use of inet_ntop, #include <arpa/inet.h> 86 87 /* === Create a thread for the current socket and process messages from the current socket === */ 88 pthread_create(malloc(sizeof(pthread_t)), NULL, (void *)(&rcv_snd), (void *)i); 89 } 90 return 0; 91 } 92 93 void quit() 94 { 95 char msg[10]; 96 while(1) 97 { 98 scanf("%s", msg); // scanf, unlike fgets, does not read the last newline entered 99 if(strcmp(msg, "quit") == 0) 100 { 101 printf("Byebye... \n"); 102 close(listenfd); 103 exit(0); 104 } 105 } 106 } 107 108 void rcv_snd(int n) 109 { 110 int len, i; 111 char name[32], mytime[32], buf[BUFFSIZE]; 112 time_t ticks; 113 int ret; 114 115 // Get the name of the socket user corresponding to this thread 116 write(connfd[n], "your name: ", strlen("your name: ")); 117 len = read(connfd[n], name, 32); 118 if(len > 0) 119 name[len-1] = '\0'; // strip newline 120 strcpy(buf, name); 121 strcat(buf, "\tjoin in\n\0"); 122 // Tell all users that the current user has joined 123 for(i=0; i<MAXMEM; i++) 124 { 125 if(connfd[i] != -1) 126 write(connfd[i], buf, strlen(buf)); 127 } 128 129 while(1) 130 { 131 char temp[BUFFSIZE]; 132 if((len=read(connfd[n], temp, BUFFSIZE)) > 0) 133 { 134 temp[len-1] = '\0'; 135 // When the user enters bye, the current user exits 136 if(strcmp(temp, "bye") == 0) 137 { 138 close(connfd[n]); 139 connfd[n] = -1; 140 pthread_exit(&ret); 141 } 142 ticks = time(NULL); 143 sprintf(mytime, "%.24s\r\n", ctime(&ticks)); 144 //write(connfd[n], mytime, strlen(mytime)); 145 strcpy(buf, name); 146 strcat(buf, "\t"); 147 strcat(buf, mytime); 148 strcat(buf, "\r\t"); 149 strcat(buf, temp); 150 strcat(buf, "\n"); 151 152 for(i=0; i<MAXMEM; i++) 153 { 154 if(connfd[i] != -1) 155 write(connfd[i], buf, strlen(buf)); 156 } 157 } 158 } 159 160 }source code client.c
1 /* 2 * FILE: client.c 3 * DATE: 20180206 4 * ============== 5 */ 6 7 #include <stdio.h> 8 #include <stdlib.h> 9 #include <string.h> 10 11 #include <netinet/in.h> 12 13 #define BUFFSIZE 128 14 #define HOST_IP "192.168.159.3" 15 #define PORT 8000 16 17 int sockfd; 18 19 void snd(); 20 21 int main() 22 { 23 pthread_t thread; // pthread_t thread, add -lpthread when gcc compiles 24 struct sockaddr_in serv_addr; // struct sockaddr_in 25 char buf[BUFFSIZE]; 26 // Initialize the server address structure 27 bzero(&serv_addr, sizeof(struct sockaddr_in)); // bzero 清零 28 serv_addr.sin_family = AF_INET; // sin_family AF_INET 29 serv_addr.sin_port = htons(PORT); // sin_port htons(PORT) 30 inet_pton(HOST_IP, &serv_addr.sin_addr); // inet_pton 31 // Create client socket 32 sockfd = socket(AF_INET, SOCK_STREAM, 0); // socket creates a socket 33 if(sockfd < 0) 34 { 35 perror("fail to socket"); 36 exit(-1); 37 } 38 // Establish a connection with the server 39 printf("connecting... \n"); 40 if(connect(sockfd, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) // connect 41 { 42 perror("fail to connect"); 43 exit(-2); 44 } 45 /* === The program is divided into two threads from here === */ 46 // Create a thread that sends a message and call the function snd that sends a message 47 pthread_create(&thread, NULL, (void *)(&snd), NULL); // pthread_create 48 // Thread receiving message 49 while(1) 50 { 51 int len; 52 if((len=read(sockfd, buf, BUFFSIZE)) > 0) // read reads the communication socket 53 { 54 buf[len] = '\0'; // Add a terminator to avoid displaying the content left in the buffer 55 printf("\n%s", buf); 56 fflush(stdout); // fflush flushes standard output to ensure timely display of content 57 } 58 } 59 return 0; 60 } 61 62 // function to send message 63 void snd() 64 { 65 char name[32], buf[BUFFSIZE]; 66 67 fgets(name, 32, stdin); // fgets will read the newline after the input string 68 write(sockfd, name, strlen(name)); // write writes to the communication socket 69 while(1) 70 { 71 fgets(buf, BUFFSIZE, stdin); 72 write(sockfd, buf, strlen(buf)); 73 if(strcmp(buf, "bye\n") == 0) // Note the \n here 74 exit(0); 75 } 76 }