Linux网络编程之多进程模型编程与一个使用进程池实现的CGI服务器

NO.1

一:什么是多进程模型

多进程模型是服务器在接收到大量高并发客户端访问时,通过创建多个子进程来与客户端进行通信。单进程阻塞在read()系统调用的时候,会导致服务器无法响应到其他的连接请求。这时可以通过fork()函数创建出多个子进程来处理业务,而主进程继续循环accept()其他客户连接,子进程实施具体的通信细节。

二:fork函数详解

NAME
       fork - create a child process       

SYNOPSIS
       #include <unistd.h>
 
       pid_t fork(void);
DESCRIPTION
       fork()  creates  a  new  process by duplicating(复制) the calling process.  The new process, referred to as the child, is an exact(准确的)
       duplicate of the calling process, referred to as the parent, except for the following points:          

       *  The child has its own unique process ID, and this PID does not match the ID of any existing process group (setpgid(2)).

       *  The child's parent process ID is the same as the parent's process ID.

       *  The child does not inherit(继承) its parent's memory locks (mlock(2), mlockall(2)).

       *  Process resource utilizations(利用) (getrusage(2)) and CPU time counters (times(2)) are reset to zero in the child.

       *  The child's set of pending(挂起) signals is initially empty (sigpending(2)).

       *  The child does not inherit semaphore(信号量) adjustments from its parent (semop(2)).

       *  The child does not inherit record(记录) locks from its parent (fcntl(2)).

       *  The child does not inherit timers from its parent (setitimer(2), alarm(2), timer_create(2)).

       ......

RETURN VALUE
       On success, the PID of the child process is returned in the parent, and 0 is returned in  the  child.   On  failure,  -1  is
       returned in the parent, no child process is created, and errno is set appropriately(适当的).                       

ERRORS
       EAGAIN
fork()  cannot  allocate  sufficient(足够的)  memory  to  copy the parent's page tables and allocate a task structure for the child.

       EAGAIN It was not possible to create a new process because the caller's RLIMIT_NPROC(用户可拥有的最大进程数) resource  limit  was  encountered(冲突).  

              To exceed this limit, the process must have either the CAP_SYS_ADMIN or the CAP_SYS_RESOURCE capability.

       ENOMEM fork() failed to allocate the necessary kernel structures because memory is tight(紧的).

       ENOSYS fork() is not supported on this platform(平台) (for example, hardware without a Memory-Management Unit).

所以由上可以总结出我们使用fork的“套路”:

pid_t pid;      //pid_t是Process ID _Type的缩写,其实是宏定义下的unsigned int类型

pid = fork();   //调用fork函数
if(pid == -1)   //如果返回值为-1,函数执行出错
	ERR_EXIT("fork error\n");
else if(pid == 0){           //如果返回值为0,启动一个子进程
	close(listenfd);         //子进程负责通信细节,关闭监听套接字
	do_service(connfd);      //通信执行函数
	exit(EXIT_SUCCESS);      //do_service结束后,子进程已无用,在此处销毁
}
else                         //父进程
	close(connfd);           //父进程仍然循环accept

三:服务器代码示例

下面是一个简单的回射服务器代码,服务器将客户端发送的代码回给客户端。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/types.h>

#define ERR_EXIT(sz) \
		do{ \
			perror(sz); \
			exit(EXIT_FAILURE); \
		}while(0)

void do_service(int connfd)
{
	char recvbuf[1024];
	for(; ;){
		memset(recvbuf, 0, sizeof(recvbuf));
		
		ssize_t ret = read(connfd, recvbuf, sizeof(recvbuf));
		if(ret == 0){
			fprintf(stdout, "client close\n");
			break;
		}			
		
		fputs(recvbuf, stdout);
		write(connfd, recvbuf, strlen(recvbuf));
		memset(recvbuf, 0, sizeof(recvbuf));
	}
}

int main(void)
{
	struct sockaddr_in servaddr;
	int listenfd;

	if( (listenfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)     //创建监听套接字,选择TCP协议
			ERR_EXIT("sockfd err");  

	memset(&servaddr, 0, sizeof(servaddr));
	servaddr.sin_family = AF_INET;                  //TCP协议族AF_INET或PF_INET,这两个宏实际上值是一样的
	servaddr.sin_port = htons(8888);                //端口8888
	servaddr.sin_addr.s_addr = INADDR_ANY;          //选择为本地任意地址

	int on 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值