Multi-process-based network chat program

Source: Internet
Author: User

Reference: Linux high Performance Server programming. Swimming double

The program is simple: The program uses shared memory to synchronize between processes, because it is only the same time to read shared memory. So no practical to lock. The function of the program is that the server listens for network connections, and when there is a client connection, the server creates a child process to process the connection.

Each child process only takes care of its own client and communicates with the parent process. When a child process reads data from the client, it puts the data into shared memory, and each child process has its own space on the shared memory. Therefore does not appear at the same time write.

Put it up and notify the parent process, said: "There is new data on the shared memory arrives, then the parent process notifies other child processes, go to the location to read the data, send the data to their client." Realize the effect of group chat. This program is a good example for people who have just started learning about multi-process programming and is written to familiarize themselves.


Server code: Need to add-LRT option when compiling

#include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h># Include <stdio.h> #include <unistd.h> #include <errno.h> #include <string.h> #include < fcntl.h> #include <stdlib.h> #include <sys/epoll.h> #include <signal.h> #include <sys/wait.h > #include <sys/mman.h> #include <sys/stat.h> #include <fcntl.h> #define USER_LIMIT 5#define BUFFER _size 1024#define fd_limit 65535#define max_event_number 1024#define process_limit 65536/* handles the necessary data for a client connection */struct  Client_data{sockaddr_in address;int connfd;/* Client's FD */pid_t pid;/* handles the PID */int pipefd[2];/* of this connected subprocess and the pipeline */};int for parent process communication sig_pipefd[2];//when a signal occurs. For the parent process own communication char* share_mem;int user_count = 0; Current number of customers client_data* users = 0; int* sub_process = 0;static Const char* shm_name = "/my_share_memory"; int maxevents = 100;bool Stop_child = False;void Set Nonblock (int fd) {int flag = FCNTL (FD,F_GETFL); assert (flag! =-1); Fcntl (Fd,f_setfl,flag| O_nonblock);} void addfd (int epollfd,int fd) {epoll_event ee;ee.data.fd = fd;ee.events = Epollin | Epollet;epoll_ctl (Epollfd,epoll_ctl_add,fd,&ee); Setnonblock (FD);} void Sig_handler (int sig) {int Save_errno = errno;int msg = sig;send (sig_pipefd[1], (char*) &msg,1,0); errno = Save_ errno;//Recovery error value}void child_sig_handler (int sig) {Stop_child = true;} void Addsig (int sig,void (*handler) (int), bool restart = true) {struct sigaction sa;memset (&sa, ' n ', sizeof (SA)); Sa.sa_handler = handler;if (restart) sa.sa_flags |= sa_restart;sigfillset (&sa.sa_mask);//function? Assert (Sigaction (sig , &sa,null)! =-1);} /* Handler function for child process. The IDX represents the number of client connections processed by the child process, and users represents an array of all client connection data, Share_mem represents the starting address of the shared memory */int run_child (int idx,client_data* users,char* SHARE_MEM) {int CONNFD = Users[idx].connfd;int PIPEFD = Users[idx].pipefd[1];int EPOLLFD = epoll_create (100);// The event handler for the child process asserts (EPOLLFD! =-1); ADDFD (EPOLLFD,CONNFD);//Communication with Client ADDFD (EPOLLFD,PIPEFD);//communication with parent process Addsig (sigterm,child _sig_handler,false); Epoll_event Events[maxevents];int REt;while (!stop_child) {int number = epoll_wait (epollfd,events,maxevents,-1), if (number < 0 && errno! = eintr) { printf ("Epoll error\n"); int i;for (i = 0;i < number;i++) {int sockfd = events[i].data.fd;if (sockfd = = Connfd && (events[i].events & E Pollin)//client sends the data {memset (share_mem+idx*buffer_size, ' \ n ', buffer_size);/* Reads the client data into the appropriate read cache. The read cache is a section of shared memory */ret = recv (sockfd,share_mem+idx*buffer_size,buffer_size-1,0); if (Ret < 0 && errno! = Eagain) { printf ("recv error\n"); stop_child = true;} else if (ret = = 0) {printf ("Client close\n"); stop_child = true;} else {Send (PIPEFD, (char*) &idx,sizeof (IDX), 0);//Tell the parent process that "I" received the data}}/* the parent process notifies me that the data for the first client is sent to the client I am responsible for */else if ( SOCKFD = = Pipefd && (events[i].events & Epollin)) {int client = 0;ret = Recv (SOCKFD, (char*) &client,sizeof ( Client), 0); if (Ret < 0 && errno! = eagain) Stop_child = True;else if (ret = = 0) Stop_child = true;else{send (connfd , share_mem+client*buffer_size,buffer_size,0);}}} Close (connFD); close (PIPEFD); close (EPOLLFD); return 0;} int main (int argc,char* argv[]) {if (argc! = 3) {printf ("usage%s server_ip server_port \ n", basename (Argv[0])); return-1;} sockaddr_in server;server.sin_family = Af_inet;inet_pton (af_inet,argv[1],&server.sin_addr); server.sin_port = Htons (Atoi (argv[2])); int LISTENFD = socket (af_inet,sock_stream,0); assert (LISTENFD! =-1); int opt = 1;int ret = setsockopt (Listenfd,sol_socket,so_reuseaddr,&opt,sizeof (opt)); assert (ret = = 0); ret = bind (LISTENFD, const sockaddr*) & Server,sizeof (server)); assert (ret! =-1); ret = Listen (listenfd,100); assert (ret! =-1);/* Initialize connection pool */user_count = 0;users = n EW client_data[user_limit+1];sub_process = new Int[process_limit];int i;for (i = 0; i < process_limit;++i) {sub_process [I] =-1;} /* Epoll initialization */int EPOLLFD = epoll_create (+), assert (EPOLLFD! =-1); ADDFD (EPOLLFD,LISTENFD);//monitor network connection Portret = Socketpair (AF_UNIX,SOCK_STREAM,0,SIG_PIPEFD);//When a signal occurs, the parent process uses its own communication assert (ret! =-1); Setnonblock (sig_pipefd[1]);// UNIX domain sockets, number No. 0 porT used for signal processing function ADDFD (epollfd,sig_pipefd[0]);//The main process listens to the UNIX domain socket number 1th port/* set signal processing function */Addsig (Sigchld,sig_handler); Addsig ( sigpipe,sig_ign); Addsig (Sigint,sig_handler); Addsig (Sigterm,sig_handler);/* Create shared memory, read cache for all client socket connections */int SHMFD = Shm_open (shm_name,o_creat| o_rdwr,0666); assert (SHMFD! =-1); ret = Ftruncate (shmfd,user_limit*buffer_size);//Set SHMFD size assert (ret! =-1); share_ MEM = (char*) mmap (null,user_limit*buffer_size,prot_read| prot_write,map_shared,shmfd,0); assert (Share_mem! = map_failed); close (SHMFD);/* Enter Epoll event loop */bool Stop_server = False ; bool Terminate = False;epoll_event Events[maxevents];while (!stop_server) {int number = Epoll_wait (epollfd,events, MAXEVENTS,-1), if (number < 0 && errno! = eintr) {printf ("Epoll error\n"); for (i = 0;i < number;i++) {int SOCKFD = events[i].data.fd;/* New Client Connection */if (SOCKFD = = listenfd) {sockaddr_in Client;socklen_ T Clilen = sizeof (client), int connfd = Accept (LISTENFD, (struct sockaddr*) &client,&clilen), if (CONNFD < 0) { printf ("Accept errOr\n "); continue;} if (User_count >= user_limit) {Const char* info = "To many users\n";p rintf ("%s\n", info); Send (Connfd,info,strlen (info) , 0); close (connfd); continue;} /* Save data related to User_count customer connection */users[user_count].address = CLIENT;USERS[USER_COUNT].CONNFD = Connfd;ret = Socketpair (AF_ UNIX,SOCK_STREAM,0,USERS[USER_COUNT].PIPEFD); assert (ret! =-1);p id_t pid = fork (), if (PID < 0) {close (CONNFD); Continue;} if (PID = = 0)//Sub-process {close (sig_pipefd[0]); Close (sig_pipefd[1]); Close (users[user_count].pipefd[0]);//Sub-process close 0portclose (LISTENFD); close (EPOLLFD); Run_child (USER_COUNT,USERS,SHARE_MEM);//Sub-process Handler Munmap ((void*) share_mem,user_limit* Buffer_size); exit (0);} else/parent Process {Close (users[user_count].pipefd[1]);//parent process close 1portclose (CONNFD); ADDFD (epollfd,users[user_count].pipefd[ 0]); users[user_count].pid = Pid;sub_process[pid] = User_count;user_count + +;}} /* Processing signal Events */else if (sockfd ==sig_pipefd[0] && events[i].events & epollin) {int Sig;char Signals[1024];ret = re CV (sockfd,signals,sizeof (signals), 0); if (rET < 0 && ret! = eagain) {printf ("recv error\n"); continue;} if (ret = = 0) continue;for (i = 0; i < ret; + + i) {switch (Signals[i]) {case SIGCHLD://Sub-process closed {pid_t Pid;int status;while (pi D = waitpid ( -1,&status,wnohang)) > 0) {/* Gets the number of the client connection being closed with the PID of the child process */int Del_user = sub_process[pid];sub_process[ Del_user] = -1;/* Clear the relevant data used by Del_user customer connection */epoll_ctl (epollfd,epoll_ctl_del,users[del_user].pipefd[0],0); Close ( USERS[DEL_USER].PIPEFD[0]);/* Moves the last client connection information to that location to ensure that the 0~user_count-1 direct connection is alive */users[del_user] = Users[--user_ Count];sub_process[users[del_user].pid] = Del_user;} if (terminate && User_count = = 0) Stop_server = true;break;} Case Sigint:case SIGTERM://end server process {printf ("Kill all of the child now\n"), for (i = 0; i < user_count;++i) {pid_t PID = use Rs[i].pid;kill (pid,sigterm);} Terminate = true;//Here is not stop_sever to wait for all child processes to end before closing the break;} Default:break;}}} /* A subprocess writes data to the parent process */else if (events[i].events & epollin) {int child;ret = recv (SOCKFD, (char*) &child,sizeof (child ), 0); if(Ret < 0 && errno! = eagain) Continue;else if (ret = = 0) continue;printf ("Read data from child accross pipe\n"); f or (i = 0; i < user_count;i++) {if (I! = child) {printf ("Send data to Child accross pipe\n"); Send (Users[i].pipefd[0], (char* ) &child,sizeof (Child), 0);}}}} Close (LISTENFD); close (EPOLLFD); close (sig_pipefd[0]); Close (sig_pipefd[1]); Shm_unlink (Shm_name);d elete[] users; Delete[] Sub_process;return 0;}


Client code (simpler). No gaze is given):
#define _gnu_source 1#include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> #include <arpa/inet.h> #include <assert.h> #include <stdio.h> #include <unistd.h> #include <string.h > #include <stdlib.h> #include <poll.h> #include <fcntl.h> #define BUFFER_SIZE 64int Main (int argc,        char* argv[]) {if (argc <= 2) {printf ("Usage:%s ip_address port_number\n", basename (Argv[0]));    return 1;    } const char* IP = argv[1];    int port = atoi (argv[2]);    struct sockaddr_in server_address;    Bzero (&server_address, sizeof (server_address));    server_address.sin_family = af_inet;    Inet_pton (Af_inet, IP, &server_address.sin_addr);    Server_address.sin_port = htons (port);    int SOCKFD = socket (pf_inet, sock_stream, 0);    ASSERT (sockfd >= 0); if (Connect (sockfd, struct sockaddr*) &server_address, sizeof (server_address)) < 0) {printf ("Co NnectiOn failed\n ");        Close (SOCKFD);    return 1;    } POLLFD fds[2];    FDS[0].FD = 0;    Fds[0].events = Pollin;    fds[0].revents = 0;    FDS[1].FD = SOCKFD; fds[1].events = Pollin |    Pollrdhup;    fds[1].revents = 0;    Char Read_buf[buffer_size];    int pipefd[2];    int ret = pipe (PIPEFD);    ASSERT (Ret! =-1);        while (1) {ret = poll (FDS, 2,-1);            if (Ret < 0) {printf ("poll failure\n");        Break            } if (Fds[1].revents & pollrdhup) {printf ("server close the connection\n");        Break            } else if (Fds[1].revents & Pollin) {memset (read_buf, ' + ', buffer_size);    int len = recv (FDS[1].FD, Read_buf, buffer_size-1, 0); int i;        for (i = 0;i<len;i++) printf ("%c", Read_buf[i]); } if (Fds[0].revents & pollin) {ret = splice (0, NULL, pipefd[1], NULL, 32768, Splice_f_mor E | Splice_f_move);            ret = Splice (pipefd[0], NULL, SOCKFD, NULL, 32768, Splice_f_more |        Splice_f_move);    }} close (SOCKFD); return 0;}


Multi-process-based network chat program

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.