Since the beginning of Learning Linux network programming to write a chat room, initially intended to use a multi-process way to write, but found that the communication between the process is a bit cumbersome, and the cost is also large, and then want to use multi-threaded can be realized, so then went to see the Linux thread usage, actually only need to know Pthread_create almost, so the hands open dry, with two days, the process of debugging is very painful, the first plan to use pure C to masturbate, then use a simple array to store the client connection information, but there are some strange problems in the run, do not know whether to access the critical resources, And the mutual exclusion between the threads and so on; Strangely, when the use of STL's set or map problem solved, but the internet search found that STL is not thread-safe, as to what is the problem of the moment do not want to tangle, may be some other small details of the error bar. First put the code:
First is the necessary header file Header.h:
#ifndef __header_h#define__header_h#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/socket.h>#include<netinet/inch.h>#include<arpa/inet.h>#include<error.h>#include<signal.h>#include<sys/wait.h>#include<assert.h>#include<pthread.h>#defineBOOL int//The 3 lines is for C originally#defineTrue 1#defineFalse 0#definePORT 9003#defineBuf_len 1024//Buffer size#defineMax_connection 6//Maximum number of connections allowed by the server, which can be changed by itself#definefor (i,s,t) for (i = (s); I! = (t); ++i)#endif //__header_h
Then there is the client part client.cpp, which is relatively simple:
#include"header.h"//the thread function that the client receives the messagevoid* RECV_FUNC (void*args) { CharBuf[buf_len]; intSOCK_FD = * (int*) args; while(true) { intn = recv (sock_fd, buf, Buf_len,0); if(N <=0) Break;//This sentence is very important, at first do not know can use this to determine whether the communication is over, with some other very wonderful practice to end and close sock_fd to avoid the appearance of close_wait and Fin_wait2 state t.tWrite (Stdout_fileno, buf, N); } close (SOCK_FD); Exit (0);}//processing functions for communication between client and servervoidProcessintsock_fd) {pthread_t TD; Pthread_create (&TD, NULL, Recv_func, (void*) &SOCK_FD);//A new thread to receive the message, avoid the first read write the original mode, at first put it in the while loop inside, tears collapse ... CharBuf[buf_len]; while(true) { intn =Read (Stdin_fileno, buf, Buf_len); Buf[n++] =' /';//looks like the standard read-in will not have a string terminator, you need to manually addSend (SOCK_FD, buf, N,0); } close (SOCK_FD);}intMainintargcChar*argv[]) {Assert (argc==2); structsockaddr_in CLI; Bzero (&CLI,sizeof(CLI)); Cli.sin_family=af_inet; Cli.sin_addr.s_addr=htonl (Inaddr_any); Cli.sin_port= Htons (PORT);//less htons words will not connect, because the small end of the machine reason??? intsc = socket (af_inet, Sock_stream,0); if(SC <0) {perror ("Socket Error"); Exit (-1); } Inet_pton (Af_inet, argv[1], & (CLI.SIN_ADDR));//use the first parameter as the address on the server side of the connection intErr = Connect (SC, (structsockaddr*) &CLI,sizeof(CLI)); if(Err <0) {perror ("Connect Error"); Exit (-2); } process (SC); Close (SC); return 0;}
Finally, the service-side server.cpp:
#include <map>#include"header.h"usingStd::map;map<int,structSockaddr_in*> socks;//used to record each client, the key is the file descriptor that communicates with the client socket, and the value is the sockaddr_in information of the corresponding client//mass message to all clients in socksInlinevoidSend_all (Const Char*buf,intLen) { for(Auto it = Socks.begin (); It! = Socks.end (); + +it) send (it->first, buf, Len,0);}//the thread function that receives the message from the end of the servicevoid* RECV_FUNC (void*args) { intCFD = * (int*) args; CharBuf[buf_len]; while(true) { intn = recv (CfD, buf, Buf_len,0); if(N <=0) Break;//The key sentence, used as a judgment to end the communicationWrite (Stdout_fileno, buf, N); if(strcmp (BUF,"bye\n") ==0) {//if the client's bye is received, the communication is terminated and the corresponding file descriptor is removed from the socks, and the dynamically requested space should be released before the deletionprintf"close connection with client%d.\n", CFD); Free(SOCKS[CFD]); Socks.erase (CFD); Break; } send_all (buf, N); //mass message to all connected clients} close (CFD); //Close the file descriptor that communicates with this client}//A thread function that communicates with a clientvoid* Process (void*argv) {pthread_t TD; Pthread_create (&TD, NULL, Recv_func, (void*) argv);//a new thread is opened in the main handler function to receive the message from the client intsc = * (int*) argv; CharBuf[buf_len]; while(true) { intn =Read (Stdin_fileno, buf, Buf_len); Buf[n++] =' /';//You need to manually add the string terminator as you would the clientSend_all (buf, N);//the server's own information input needs to be sent to all clients} close (SC);}intMainintargcChar*argv[]) { structsockaddr_in serv; Bzero (&serv,sizeof(serv)); Serv.sin_family=af_inet; Serv.sin_addr.s_addr=htonl (Inaddr_any); Serv.sin_port=htons (PORT); intSS = Socket (Af_inet, Sock_stream,0); if(SS <0) {perror ("Socket Error"); return 1; } intErr = bind (ss, (structsockaddr*) &serv,sizeof(serv)); if(Err <0) {perror ("bind error"); return 2; } Err= Listen (ss,2); if(Err <0) {perror ("Listen error"); return 3; } socks.clear (); //Clear Mapsocklen_t len =sizeof(structsockaddr); while(true) { structsockaddr_in *cli_addr = (structsockaddr_in*)malloc(sizeof(structsockaddr_in)); intsc = Accept (ss, (structsockaddr*) cli_addr, &Len); if(SC <0) { Free(CLI_ADDR); Continue; } if(Socks.size () >= max_connection) {//When the maximum number of connections is going to be exceeded, let the client wait for a moment. Charbuf[ -] ="connections is too much, please waiting...\n"; Send (SC, buf, strlen (BUF)+1,0); Close (SC); Free(CLI_ADDR); Continue; } SOCKS[SC]= CLI_ADDR;//point to the sockaddr_in space that corresponds to the requestprintf"Client%d connect me...\n", SC); Pthread_t TD; Pthread_create (&TD, NULL, Process, (void*) &SC);//open a thread to interact with the client of the Accept } return 0;}
Makefile File:
All:server clientserver:server.cpp g++-std=c++11-o server server.cpp-lpthreadclient:client.cpp g++-std=c+ +11-o client Client.cpp-lpthreadclean: rm-f *.O
In my Ubuntu 14.04 64-bit machine tested no problem, the client and the server can be normal interaction and exit, through the server to receive messages sent by other clients, the runtime CPU and memory consumption is normal, will not produce any strange bug. Temporarily write only a terminal interface, the client's UI later to get it ~
Chat rooms written under Linux using multithreading