Linux Client/Server programming paradigm 2 & mdash; Concurrent Server (process pool), linux paradigm

Source: Internet
Author: User
Tags epoll sendmsg

Linux Client/Server programming paradigm 2 -- Concurrent Server (process pool), linux paradigm
Introduction

Let the server call fork to create a sub-process pool during the startup phase and process client requests through sub-processes. Use socketpair to communicate with the parent process (to facilitate the use of sendmsg and recvmsg, if the anonymous pipeline is used, the above two functions cannot be used ). The following is an analysis of TCP.

The server uses select Round Robin to monitor the passive socket fd_listen for client requests and socketpair for parent-child communication. When the client has a request, the server sends the socket descriptor returned by accept for communication with the client to an idle sub-process through socketpair, the sub-process communicates with the client to process requests ). Therefore, the server needs to maintain a sub-process queue. Each element in the queue stores the socketpair that communicates with the sub-process and the flag indicating whether the sub-process is idle, as follows:

Typedef struct tag_chd {int s_sfd; // socketpair descriptor int s_state that communicates with the sub-process; // indicates whether the sub-process is idle} NODE, * pNODE;

Each time a sub-process processes a client request, it will send a message to the server through socketpair. After the server selects socketpair, the corresponding sub-process flag is set to idle.

Note:

1. Because the parent process first creates a sub-process, and then accept is used to communicate with the client socket descriptor fd_client, there is no fd_client information in the pcb of the sub-process. The server needs to send the fd_client to the sub-process. If you only use send to send fd_client information, the sub-process will only treat it as an integer. We need to use sendmsg to send fd_client along with its auxiliary (Control) information so that the process will regard it as a socket descriptor.

2. The parent process creates a sub-process pool in advance, and the sub-process will never exit like the server. The while loop is used in the sub-process as follows:

While (1) {readn = read (sfd, & flag, 4); // The subscript printf ("readn: % d \ n ", readn); printf (" read from father: % d \ n ", flag); recv_fd (sfd, & fd_client ); // recv_fd encapsulates recvmsg to receive the socket descriptor handle_request (fd_client) that communicates with the client; // process the client request write (sfd, & pid, sizeof (pid )); // after processing the request, notify the server through socketpair. The server sets the sub-process status to idle}

Every time a sub-process processes a client request (that is, the client exits), the sub-process will block the read and wait for receiving the next client request.

Because it is a while endless loop and there is no break statement in the endless loop, it is impossible for the sub-process to jump out of this while loop, so it will not execute the content below the while loop, this ensures that the sub-process does not end with exit and does not execute post content.

3. For the dynamic library used for compilation, see Linux network programming 9-2.0 simple encapsulation of TCP and UDP.

Function prototype
# Include <sys/types. h> # include <sys/socket. h> ssize_t recvmsg (int sockfd, struct msghdr * msg, int flags); ssize_t sendmsg (int sockfd, const struct msghdr * msg, int flags); struct msghdr {void * msg_name; /* optional address */socklen_t msg_namelen;/* size of address */struct iovec * msg_iov;/* scatter/gather array */size_t msg_iovlen; /* # elements in msg_iov */void * msg_control;/* ancillary Data, see below */socklen_t msg_controllen;/* ancillary data buffer len */int msg_flags;/* flags on received message */}; fields: struct iovec {/* Scatter/gather array items */void * iov_base;/* Starting address */size_t iov_len;/* Number of bytes to transfer */}; struct cmsghdr {socklen_t cmsg_len;/* data byte count, including header */int cmsg_level;/* originating protocol * // * such If it is a file descriptor, fill in SOL_SOCKET */int cmsg_type;/* protocol-specific type * // * if it is a file descriptor, fill in SCM_RIGHTS * // * followed by unsigned char cmsg_data []; */};/* return the value of the cmsg_len Member of the cmsghdr structure. Considering alignment, the length of the Data part is used as a parameter. */Size_t CMSG_LEN (size_t length);/* return the Data Pointer of cmsghdr. */Unsigned char * CMSG_DATA (struct cmsghdr * cmsg); CMSG_DATA () returns a pointer to the data portion of a cmsghdr. CMSG_LEN () returns the value to store in the cmsg_len member of the cmsghdr structure, taking into account any necessary alignment. it takes the data length as an argument. this is a constant expression.
NAME       socketpair - create a pair of connected socketsSYNOPSIS       #include <sys/types.h>          /* See NOTES */       #include <sys/socket.h>       int socketpair(int domain, int type, int protocol, int sv[2]);

RETURN VALUE
On success, zero is returned. On error,-1 is returned, and errno is
Set appropriately.

Code

Server. h

#ifndef __SERVER_H__#define __SERVER_H__#include "my_socket.h"#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <sys/time.h>#include <sys/select.h>#include <sys/uio.h>#include <sys/wait.h>#include <errno.h>#define SER_IP "127.0.0.1"#define SER_PORT 8888#define ST_BUSY 1#define ST_IDLE 2#define SIZE 8192#define MSG_SIZE (SIZE - 4)typedef struct tag_mag{    int msg_len ;    char msg_buf[MSG_SIZE];//8188}MSG, *pMSG;typedef struct tag_chd{    int s_sfd ;    int s_state ;}NODE, *pNODE;extern int errno ;void make_child(pNODE arr, int cnt);void child_main(int sfd) ;void handle_request(int sfd);void send_fd(int sfd, int fd_file) ;void recv_fd(int sfd, int* fd_file) ;void dispatch(pNODE arr, int cnt, int fd_client);#endif

Main. c

/*************************************** * *********************************> File Name: main. c> Author: KrisChou> Mail: zhoujx0219@163.com> Created Time: fri 05 Sep 2014 11:19:13 pm cst ********************************* ***************************************/ # include "server. h "int main (int argc, char * argv []) // exe chld_cnt {if (argc! = 2) {printf ("Usage: exe, child_cnt! \ N "); exit (1);} int child_cnt = atoi (argv [1]); pNODE arr_child = (pNODE) calloc (child_cnt, sizeof (NODE )); /* dynamic array maintenance sub-process pool */make_child (arr_child, child_cnt); int fd_listen, fd_client; my_socket (& fd_listen, MY_TCP, SER_IP, SER_PORT); my_listen (fd_listen, 10); fd_set readset, readyset; FD_ZERO (& readset); FD_ZERO (& readyset); FD_SET (fd_listen, & readset); int index; for (index = 0; index <child_cnt; index ++) {FD_SET (arr_child [index]. s_sfd, & readset);} int select_ret; struct timeval tm; while (1) {tm. TV _sec = 0; tm. TV _usec = 1000; readyset = readset; select_ret = select (1024, & readyset, NULL, NULL, & tm); if (select_ret = 0)/* Within the polling time, if no descriptor is active, 0 is returned and the polling */{continue;} else if (select_ret =-1)/* signal */{if (errno = EINTR) continues) {continue;} else {exit (1) ;}} else {if (FD_ISSET (fd_listen, & readyset) {fd_client = accept (fd_listen, NULL, NULL ); dispatch (arr_child, child_cnt, fd_client); close (fd_client) ;}for (index = 0; index <child_cnt; index ++) {if (FD_ISSET (arr_child [index]. s_sfd, & readyset) {int val; read (arr_child [index]. s_sfd, & val, 4); arr_child [index]. s_state = ST_IDLE ;}}}}}

Server. c

/*************************************** * *********************************> File Name: server. c> Author: KrisChou> Mail: zhoujx0219@163.com> Created Time: fri 05 Sep 2014 11:17:56 pm cst ********************************* ***************************************/ # include "server. h "void make_child (pNODE arr, int cnt) {int index; for (index = 0; index <cnt; index ++) {pid_t pid; int fds [2]; // fds [0]-c fds [1]-p socketpair (AF_LOCAL, SOCK_STREAM, 0, fds); pid = fork (); if (pid = 0) // child {close (fds [1]);/* use fds [0] as the sub-process to disable fds [1] */child_main (fds [0]); /* each time a sub-process is created, the sub-process enters the function (endless loop), receives the request, and processes the request. */} Else {/* initialize each sub-process in the process pool queue */arr [index]. s_sfd = fds [1]; arr [index]. s_state = ST_IDLE; close (fds [0]);/* the parent process uses fds [1] to disable fds [0] */} void child_main (int sfd) {int fd_client; int flag; int readn; pid_t pid = getpid (); while (1) {readn = read (sfd, & flag, 4); printf ("readn: % d \ n ", readn); printf (" read from father: % d \ n ", flag); recv_fd (sfd, & fd_client); handle_request (fd_client ); write (sfd, & Pid, sizeof (pid) ;}} void handle_request (int sfd) {MSG my_msg; int recvn; while (1) {memset (& my_msg, 0, sizeof (MSG); my_recv (& recvn, sfd, & my_msg, 4); if (my_msg.msg_len = 0) {break;} my_recv (NULL, sfd, my_msg.msg_buf, success); my_send (NULL, sfd, & my_msg, my_msg.msg_len + 4) ;}} void send_fd (int sfd, int fd_file) {struct msghdr my_msg; memset (& my_msg, 0, sizeof (my_msg); struct io Vec bufs [1]; char buf [32] = "hello world! \ N "; bufs [0]. iov_base = buf; bufs [0]. iov_len = strlen (buf); my_msg.msg_name = NULL; my_msg.msg_namelen = 0; my_msg.msg_iov = bufs; Signature = 1; my_msg.msg_flags = 0; struct cmsghdr * p; int cmsg_len = CMSG_LEN (sizeof (int);/* indicates the file descriptor, so sizeof (int) */p = (struct cmsghdr *) calloc (1, cmsg_len ); p-> cmsg_len = cmsg_len; p-> cmsg_level = SOL_SOCKET; p-> cmsg_type = SCM_RIGHTS; * (int *) CMSG_DATA (p) = fd_file; my_msg.msg_control = p; my_msg.msg_controllen = cmsg_len; int sendn; sendn = sendmsg (sfd, & my_msg, 0); printf ("send masg len: % d \ n", sendn );} void recv_fd (int sfd, int * fd_file) {struct msghdr my_msg; struct iovec bufs [1]; char buf1 [32] = ""; bufs [0]. iov_base = buf1; bufs [0]. iov_len = 31; my_msg.msg_name = NULL; Direction = 0; Direction = bufs; Direction = 2; my_msg.msg_flags = 0; struct cmsghdr * p; int cmsg_len = CMSG_LEN (sizeof (int )); p = (struct cmsghdr *) calloc (1, cmsg_len); my_msg.msg_control = p; my_msg.msg_controllen = cmsg_len; int recvn; recvn = recvmsg (sfd, & my_msg, 0 ); * fd_file = * (int *) CMSG_DATA (struct cmsghdr *) my_msg.msg_control); // write it as * (int *) CMSG_DATA (P) or printf ("buf1: % s, recv msg len: % d \ n ", buf1, recvn);} void dispatch (pNODE arr, int cnt, int fd_client) {int index; for (index = 0; index <cnt; index ++) {if (arr [index]. s_state = ST_IDLE) {write (arr [index]. s_sfd, & index, 4); send_fd (arr [index]. s_sfd, fd_client);/* allocates tasks to idle sub-processes and sends the socket descriptor returned by the server accept to the sub-process */arr [index]. s_state = ST_BUSY; break ;}}}

Client. c

/*************************************** * *********************************> File Name: client. c> Author: KrisChou> Mail: zhoujx0219@163.com> Created Time: fri 05 Sep 2014 03:48:27 pm cst ********************************* ***************************************/ # include "my_socket.h" # define MY_IP "127.0.0.1" # define MY_PORT 6666 # define SER_IP "127.0.0.1" # define SER_PORT 8888 # define SIZE 8192 # define MSG_SIZE (SIZE-4) typedef struct tag_mag // {int msg_len; char msg_buf [MSG_SIZE]; // 8188} MSG, * pMSG; int main (int argc, char * argv []) {int sfd; my_socket (& sfd, MY_TCP, MY_IP, atoi (argv [1]); my_connect (sfd, SER_IP, SER_PORT); MSG my_msg; while (memset (& my_msg, 0, sizeof (MSG), fgets (my_msg.msg_buf, MSG_SIZE, stdin )! = NULL) {my_msg.msg_len = strlen (my_msg.msg_buf); my_send (NULL, sfd, & my_msg, 4 + my_msg.msg_len); memset (& my_msg, 0, sizeof (MSG )); my_recv (NULL, sfd, & my_msg, 4); my_recv (NULL, sfd, & my_msg.msg_buf, my_msg.msg_len); printf ("recv from server: % s \ n ", my_msg.msg_buf);}/* When the client exits, a message with a length of 0 is sent to the server to notify the server to exit */memset (& my_msg, 0, sizeof (MSG )); my_send (NULL, sfd, & my_msg, 4 + my_msg.msg_len); close (sfd );}

The compilation is as follows:

gcc -o s server.c main.c -lmy_socket -I/home/purple/includegcc -o c client.c -lmy_socket -I/home/purple/include

In linux network programming, the main functions of the TCP Concurrent Server PASS Parameters to the two same thread functions respectively. Will the latter parameter overwrite the previous one?

Wangyi technology's proxy server is a regular professional. My friend recommended me to use it very well. Hope to help you

How to Improve the concurrency and performance of the linux socket server?

Epoll is prone to errors when receiving data. Can you check the bugs in epoll?
Can libevent meet your needs?

 

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.