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
Then run the client a few more times and you can see that the number of processes increases
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