Linux programming-Multi-Client (15th chapter)

Source: Internet
Author: User
Tags readable

More than 15.4 customers so far, this chapter has been about using sockets to implement local and cross-network client/server systems. Once the connection is established, the socket connection behaves like an open underlying file descriptor, and in many ways resembles a bidirectional pipeline.
Now consider having a situation where multiple customers connect to a server at the same timeThe server program creates a new socket when it accepts a new connection from the customer, and the original listener socket is retained to continue listening for subsequent connections. If the server does not immediately accept subsequent connections, they will be placed in the queue for processing.
The fact that the original socket is still available and the socket behaves like a file descriptor provides a way to serve multiple customers at the same time. If the server calls fork to create a second copy for itself, the open socket will be inherited by the new child process. The new subprocess can communicate with the connected customer. The master server process can continue to accept future client connections. These changes are very easy for the server program.
Because child processes are created, but do not wait for their completion, all must schedule the server to ignore SIGCHLD signals to avoid zombie processes.
Programs can serve multiple client servers at the same time to write programs server4.c
/************************************************************************* > File name:server4.c > description:server4.c > Author:liubingbing > Created time:2015 July 25 Saturday 17:22 52 seconds > Other:ser ver4.c ************************************************************************/#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/types.h> #include <sys/socket.h> #include < Netinet/in.h> #include <signal.h>int main () {int server_sockfd, client_sockfd;int server_len, Client_len; struct sockaddr_in server_address;struct sockaddr_in client_address;/* socket function creates socket */SERVER_SOCKFD = socket (AF_INET, Sock_stream, 0);/* The socket address is specified by the struct sockaddr_in, a af_inet socket is fully determined by its domain, IP address, and port number */server_address.sin_family = Af_inet; SERVER_ADDRESS.SIN_ADDR.S_ADDR = htonl (inaddr_any); server_address.sin_port = Htons (9734); server_len = sizeof (server_ address);/* The BIND function names the socket so that the af_inet socket is associated to an IP port number * Additionally, bind calls need to be converted to a specific address structure of love to point to a generic address type (StruCT sockaddr *) */bind (SERVER_SOCKFD, (struct sockaddr *) &server_address, Server_len);/* Create a connection queue, ignoring the exit details of the child process, Waiting for the arrival of the customer */listen (SERVER_SOCKFD, 5), Signal (SIGCHLD, sig_ign), while (1) {char ch;printf ("Server waiting\n");/* Accept connection */ Client_len = sizeof (client_address), client_sockfd = Accept (SERVER_SOCKFD, (struct sockaddr *) &client_address, &client_len);/* Creates a child process for this customer through a fork call, and then tests the parent process or child process */if (fork () = = 0) {Read (CLIENT_SOCKFD, &ch, 1); sleep (5); ch ++;write (CLIENT_SOCKFD, &ch, 1); close (CLIENT_SOCKFD); exit (0);} else {close (CLIENT_SOCKFD);}}}
The 5-second delay that is inserted when processing a customer request is to simulate the server's compute time or database access time. If you do this in the previous server, the Client3 will take 5 seconds to run each time, and the new server can handle multiple CLIENT3 programs at the same time, which will take more than 5 seconds to complete .. As shown below:

The Program resolution server program will now create a new subprocess to process each customer, so you will see several servers waiting for messages, while the main process will continue to wait for new connections. The SERVER4 process is waiting for new customers, While 3 client processes are being serviced by 3 server sub-processes. After a 5-second pause, all customers get their results and end up running. The server's child processes are also exited, leaving only the primary server process running.
Server programs processing multiple customers with the fork function, but in a database application, this may not be the best solution because the server program can be quite large, and there is a need to reconcile multiple server replicas in database accessIn fact, what is really needed is to allow a single server process to process multiple customers without blocking and not waiting for a customer request to arrive. The solution to this problem is to design how to handle multiple open file descriptors at the same time, and it is not limited to sockets, see the next section of the select System call.
15.4.1 select System calls when writing a Linux application, you often encounter situations where you need to check several inputs to determine what to do next. For example, a communication program such as a terminal emulator needs to efficiently read both the keyboard and the serial port. If you are in a single-user system, run a The "Busy Wait" loop is still acceptable, and it keeps scanning the input settings to see if there is data and reads it if there is data available, but this practice consumes CPU time.
The select System call allows the program to wait for the input arrival (or completion of the output) on multiple underlying file descriptors at the same time. This means that the terminal emulator can always be blocked until something can be done. Similarly, a server can handle multiple customers by waiting for a request to arrive at the same time on multiple open sockets.
The SELECT function operates on the data structure Fd_set, which is a collection of open file descriptors, with a defined set of macros that can be used to control these collections:
#include <sys/types.h> #include <sys/time.h>void fd_zero (fd_set *fdset); void fd_clr (int FD, fd_set *fdset); void Fd_set (int fd, fd_set *fdset), void fd_isset (int fd, fd_set *fdset);
The Fd_zero is used to initialize the Fd_set to an empty collection.
Fd_set and FD_CLR are used to set and clear the file descriptors passed by parameter FD in the collection respectively.
If the file descriptor pointed to by the parameter FD in the Fd_isset macro is an element in the Fd_set collection that is pointed to by the parameter Fdset, Fd_isset returns a value other than 0.
The maximum number of file descriptors that can be accommodated in a FD_SET structure is specified by the constant fd_setsize.
The Select function can also use a timeout value to prevent indefinite blocking, which is given by a TIMEVAL structure defined in the file sys/time.h, which consists of a few members:
struct Timeval {    time_t tv_sec;    /* seconds */    long tv_usec;    /* microseconds */};
Type time_t is defined as an integer type in the header file sys/types.h.
The prototype of the select System call is as follows:
#include <sys/types.h> #include <sys/time.h>int select (int Nfds, fd_set *readfds, Fd_set *writefds, Fd_set * Errorfds, struct timeval *timeout);
The select call is used in the test file descriptor collection, whether a file descriptor is already in a readable or writable state or an error state, and it blocks to wait for a file descriptor to enter these states.
The parameter Nfds specifies the number of file descriptors that need to be tested, and the test descriptor access from 0 to nfds-1.3 descriptor sets can be set to a null pointer, indicating that the corresponding test is not performed.
The Select function returns when the descriptor in the Readfds collection is readable, the descriptor in the Writefds collection is writable, or a descriptor in the Errorfds collection encounters an error condition if none of the 3 cases have occurred. Select will return after the timeout specified by timeout. If the timeout parameter is a null pointer and there is no activity on the socket, the call will block the next one.
When select returns, the Descriptor collection is modified to indicate which descriptors are in a readable, writable, or erroneous state. You can test the descriptor with Fd_isset to find the descriptor that needs attention. You can modify the timeout value to indicate the remaining time-out, but this is not the x/ The behavior defined in the open specification. If the select is returned because of a timeout, all descriptor sets will be emptied.
The Select call returns the total number of descriptors for which the state has changed. When it fails, it returns 1 and sets errno to describe the error. Errors that may occur include: EBADF (Invalid descriptor), EINTR (returned as a result of an interrupt), EINVAL (NFS or timeout value error)

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Linux programming-Multi-Client (15th chapter)

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.