Moving on from Tutorial 1, in this chapter we will need to develop a Web server that supports concurrency and add fault tolerance

It is recommended to wrap the socket function in the new wrap_socket.c file, and create its.h file, include the file on the Server side, and rewrite part of the code on the Server side.

The wrap_socket.c file should look like this:

#include "wrap_socket.h"

#define MAXLINE 1000

void p_error(char *str) {
    printf("%s\n",str);
}
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = * /
/* Here are all socket methods wrapped */
/ * = = = = = = = = = = = = = = = = = = = = = = = = = = * /
int Socket(int family,int type,int protocol) {
    int socketfd = socket(family, type, protocol);

    if(socketfd < 0) {
        p_error("socket connect error\n");
        return - 1;
    }
    return socketfd;
}

void Bind(int fd, const struct sockaddr *sa, socklen_t len) {
    if(bind(fd, sa, len) < 0 )
        p_error("bind connect error\n");
}
void Listen(int fd,int backlog_size) {
    if(listen(fd, backlog_size) < 0)
        p_error("listen client error\n");
}
int Accept(int fd,const struct sockaddr *sa,socklen_t *len) {
    int clientfd = accept(fd, sa, len);
    if(clientfd < 0)
        p_error("can't accept clientserver\n");
    return clientfd;
}
void Connect(int fd,const struct sockaddr *sa,socklen_t len) {
    if(connect(fd, sa, len) < 0)
       p_error("connect to webserver error\n");
}
long Read(int fd, void *buf, size_t len) {
    long n;
    if((n = read(fd, buf, len)) == - 1)
        p_error("read error\n");
    return n;
}
void Write(int fd, void *buf, size_t len) {
    if(write(fd, buf, len) == - 1 )
        p_error("write error\n");
}
void Close(int fd) {
    if(close(fd) == - 1)
        p_error("close fd error\n");
}Copy the code

Of course, the corresponding wrap_socket.h should look like this:

#ifndef wrap_socket_h
#define wrap_socket_h

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// The header required by the read method
#include <unistd.h>
// The header file required by the socket method
#include <sys/socket.h>
#include <sys/types.h>
// The header file required by the htonl method
#include <netinet/in.h>
// The header file required by the inet_ntop method
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <fcntl.h>


int Socket(int family,int type,int protocol);
int num_sum(int a,int b);
void Bind(int fd, const struct sockaddr *sa, socklen_t len);
void Listen(int fd,int backlog_size);
int Accept(int fd,const struct sockaddr *sa,socklen_t *len);
void Connect(int fd,const struct sockaddr *sa,socklen_t len);
long Read(int fd, void *buf, size_t len);
void Write(int fd, void *buf, size_t len);
void Close(int fd);

#endif /* wrap_socket_h */Copy the code

We need to rewrite some of the webserver.c socket files

 listenfd = Socket(AF_INET, SOCK_STREAM, 0);
    // Initialize the myaddr parameter
    bzero(&servaddr, sizeof(servaddr)); // Clear the structure
    // Assign to the servADDR structure
    servaddr.sin_family = AF_INET;
    servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
    servaddr.sin_port = htons(SERV_PORT);

    Bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr));

    Listen(listenfd, BACKLOGSIZE);Copy the code

At this point, run the program. Tune in the bug and see if it works

Then we can try to start a Client to interact with the Server, and then start another Client to connect to the Server to see if it works. Why?

To support concurrency, fork() is needed. Find a simple example to illustrate how fork works

#include <unistd.h>  
#include <stdio.h>   
int main (a)   
{   
    pid_t fpid; //fpid represents the value returned by fork
    int count=0;  
    fpid=fork();   
    if (fpid < 0)   
        printf("error in fork!");   
    else if (fpid == 0) {  
        printf("i am the child process, my process id is %d/n",getpid());   
        printf("I am the son of my father/N");// To some people, Chinese seems more straightforward.
        count++;  
    }  
    else {  
        printf("i am the parent process, my process id is %d/n",getpid());   
        printf("I am the father/N");  
        count++;  
    }  
    printf("The result is: %d/n",count);  
    return 0;  
}Copy the code

Of course, this program will also add the fork to the concurrent processing, without further ado, offer the code

    //Accept () in an infinite loopwhile (1) {
        cliaddr_len = sizeof(cliaddr);

        //Accept() returns a connfd descriptor. Connfd = accept(listenfd, (struct sockaddr *)& cliADDR, &cliaddr_len);//The fork() method creates a process identical to the parent process pid <0Pid = = indicates that fork failed0Represents the child process PID >0Is the parent process whose pid=getpid(); pid = fork();if(pid < 0) {
            printf("fork error\n");exit(1);
        }else if(pid == 0) {
            while (1) {
                n = Read(connfd, buf, MAXLINE);
                if (n == 0) {
                    printf("the other side has been closed.\n");
                    break;
                }
                printf("received from %s at PORT %d,message is %s\n",
                       inet_ntop(AF_INET, &cliaddr.sin_addr, str, sizeof(str)),
                       ntohs(cliaddr.sin_port),buf);
                for (i = 0; i < n; i++)
                    buf[i] = toupper(buf[i]);
                write(connfd, buf, n);
            }
            Close(connfd);
            exit(0);
        }else{ Close(connfd); }}Copy the code

Here, we try to run, and then open the new client to see if it can be accessed smoothly, we can also view the process through Linux command

ps -ef | grep webserverCopy the code

So the initial boot looks like this





first_start_server.png

Then run the client a few more times and you can see that the number of processes increases





second_start_server.png

Well, that’s the end of the chapter on error handling and forking, and chapter 3 gets down to the real business of Web server development