Linux network programming using multi-process for concurrent server access

Source: Internet
Author: User
Tags socket error
A classic example of implementing concurrent access to the server using a multi-process method. A classic example of implementing concurrent access to the server using a multi-process method.
Program implementation functions:
1. the client reads a line of text from the standard input and sends it to the server.
2. after receiving the text from the client, the server returns it to the client as it is.
3. after receiving the text from the server, the client outputs the text to the standard output and continues the preceding steps.
Server process: after a listening socket is established, wait for the client to connect. after receiving a connection, create a sub-process to communicate with the client, the main process continues to wait for connections from other clients. The code is as follows:
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Define SERV_PORT 1113
# Define LISTENQ 32
# Define MAXLINE 1024
/*** Connection handler ***/
Void str_echo (int fd );
Int
Main (int argc, char * argv []) {
Int listenfd, connfd;
Pid_t childpid;
Socklen_t clilen;
Struct sockaddr_in servaddr;
Struct sockaddr_in cliaddr;
If (listenfd = socket (AF_INET, SOCK_STREAM, 0) =-1 ){
Fprintf (stderr, "Socket error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
/* Fill in the sockaddr structure on the server */
Bzero (& servaddr, sizeof (servaddr ));
Servaddr. sin_family = AF_INET;
Servaddr. sin_addr.s_addr = htonl (INADDR_ANY );
Servaddr. sin_port = htons (SERV_PORT );
/* Bind the listenfd descriptor */
If (bind (listenfd, (struct sockaddr *) (& servaddr), sizeof (struct sockaddr) =-1 ){
Fprintf (stderr, "Bind error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
/* Listen to the listenfd descriptor */
If (listen (listenfd, 5) =-1 ){
Fprintf (stderr, "Listen error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
For (;;){
Clilen = sizeof (cliaddr );
/* Server blocking until the client program establishes a connection */
If (connfd = accept (listenfd, (struct sockaddr *) (& cliaddr), & clilen) =-1 ){
Fprintf (stderr, "Accept error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
// After a client establishes a connection
If (childpid = fork () = 0) {/* sub-process */
Close (listenfd);/* close the listening socket */
Str_echo (connfd);/* process the client request */
Exit (0 );
}
Close (connfd);/* the parent process closes the connection socket and waits for other connections to arrive */
}
}
Void str_echo (int sockfd ){
Ssize_t n;
Char buf [MAXLINE];
Again:
While (n = read (sockfd, buf, MAXLINE)> 0)
Write (sockfd, buf, n );
If (n <0 & errno = EINTR) // interrupted, reentrant
Goto again;
Else if (n <0) {// error
Fprintf (stderr, "read error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
}
Client process: create a connection socket and initiate a connection request to the server. after the connection is established, wait for the standard input. after the input is complete, the entered content is sent to the server, then, the system receives the content sent by the server and outputs the received content to the standard output. The code is as follows:
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Include
# Define SERV_PORT 1113
# Define MAXLINE 1024
Void str_cli (FILE * fp, int sockfd );
Int
Main (int argc, char ** argv)
{
Int sockfd;
Struct sockaddr_in servaddr;
If (argc! = 2 ){
Fprintf (stderr, "usage: tcpcli \ N \ ");
Exit (0 );
}
If (sockfd = socket (AF_INET, SOCK_STREAM, 0) =-1 ){
Fprintf (stderr, "Socket error: % s \ n \ a", strerror (errno ));
Exit (1 );
}
/* Fill in the information of the client program on the server */
Bzero (& servaddr, sizeof (servaddr ));
Servaddr. sin_family = AF_INET;
Servaddr. sin_port = htons (SERV_PORT );
If (inet_ton (AF_INET, argv [1], & servaddr. sin_addr) <= 0 ){
Fprintf (stderr, "inet_ton Error: % s \ a \ n", strerror (errno ));
Exit (1 );
}
/* The client program initiates a connection request */
If (connect (sockfd, (struct sockaddr *) (& servaddr), sizeof (struct sockaddr) =-1 ){
Fprintf (stderr, "connect Error: % s \ a \ n", strerror (errno ));
Exit (1 );
}
Str_cli (stdin, sockfd);/* do it all */
Exit (0 );
}
Void
Str_cli (FILE * fp, int sockfd)
{
Int nbytes = 0;
Char sendline [MAXLINE], recvline [MAXLINE];
While (fgets (sendline, MAXLINE, fp )! = NULL) {// read a row from the standard input
Write (sockfd, sendline, strlen (sendline); // send this row to the server
If (nbytes = read (sockfd, recvline, MAXLINE) = 0) {// read data from the server from sockfd
Fprintf (stderr, "str_cli: server terminated prematurely \ n ");
Exit (1 );
}
Recvline [nbytes] = '\ 0 ';
Fputs (recvline, stdout );
}
}
Running result:
1. start the server program first.
Viidiot @ ubuntu $./dissrv & (run in the background)
2. start a client
Viidiot @ ubuntu $./discli 127.0.0.1
Hello, world! (Content entered by the client)
Hello, world! (Content returned by the server)
3. run the netstat-at command to check the tcp connection. you can find that the server has established a connection with the client, and the master process of the server is still listening on port 1113, wait for other connections to arrive.
Viidiot @ ubuntu $ netstat-
Tcp 0 0 *: 1113 *: * LISTEN
Tcp 0 0 localhost. localdom: 1113 localhost. localdo: 57430 ESTABLISHED
Tcp 0 0 localhost. localdo: 57430 localhost. localdom: 1113 ESTABLISHED
The client enters the EOF to end the communication.
However, when we enable multiple clients to connect to the server for communication and end the communication by pressing EOF, we can find an interesting thing in the background, that is, a large number of zombie processes. As follows:
Viidiot @ ubuntu $ ps-
PID TTY TIME CMD
19403 pts/1 00:00:00 dissrv
19405 pts/1 00:00:00 dissrv
19423 pts/1 00:00:00 dissrv
19434 pts/1 00:00:00 dissrv
19441 pts/1 00:00:00 dissrv
A large number of zombie processes are caused by a SIGCHLD signal sent to the parent process when the child process of the server is terminated. However, in our code, this signal is not captured, and the default action of this signal is ignored. therefore, to avoid the generation of zombie processes, we need to capture SIGCHLD to understand the Zombie process.
Related Article

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.