linux进程池的程序的代码,Linux网络编程-自己动手写进程池

本文介绍了如何在Linux环境中使用进程池来优化并发服务器的性能,避免动态创建进程带来的延迟和资源消耗。通过创建预定义数量的子进程,提高了响应速度并减少了进程切换开销。文中给出了一个简单的进程池示例,使用管道进行进程间通信,并展示了如何处理客户端的连接请求。此外,还讨论了信号处理函数`handle_sigchld`在子进程退出时的角色。
摘要由CSDN通过智能技术生成

并发服务器的实现中,可以通过动态的创建子进程(或子线程)来实现。这样有几个缺点:

1、动态创建进程(或线程)比较耗时间,将导致客户响应较慢

2、动态创建的子进程或子线程通常只用来为一个客户服务,这导致系统中产生了很多进程或线程,使进程或线程之间的切换消耗很多CPU时间

3、动态创建子进程是当前进程的完整映像,当前进程需要谨慎管理其分配的文件描述符,否则子进程可能复制这些资源,导致系统可用资源急剧下降,进而影响服务器性能

以上的几个缺点可以通过进程池来规避,进程池是由服务器预先创建一组子进程,一般数目在3-10之间,进程池中的所有子进程运行着相同的代码,应具有相同的属性,比如优先级、PGID等。当有新任务来时,主进程选择进程池中的一个子进程来为之服务,相比于动态创建子进程,选择一个已经存在子进程显然来得跟快。

以下是我自己参考网络资料写的一个简单的进程池示例,进程间通信使用的是管道。

该程序说明:主进程先创建两个管道,一个用于向子进程写数据,另一个用于子进程向主进程写数据。然后主进程再创建4个子进程,让4个子进程来进程处理客户的连接请求,然后给主进程发送信息,同时主进程也给子进程发送应答信息。

运行程序后的输出结果(比如端口设为60000):

0818b9ca8b590ca3270a3433284dd417.png

在浏览器中输入http://192.168.1.2:60000(192.168.1.2运行该程序的主机)后就可以看到

0818b9ca8b590ca3270a3433284dd417.png

源代码:

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define err_sys(msg) \

do { perror(msg); exit(-1); } while(0)

#define err_exit(msg) \

do { fprintf(stderr, msg); exit(-1); } while(0)

#define head200 "HTTP/1.1 200 OK \r\n"

#define head404 "HTTP/1.1 404 Not Found\r\n"

#define head503 "HTTP/1.1 503 Service unabailiable\r\n"

#define MAXCHILD 4

#define BUFFSIZE 1024

typedef struct

{

pid_t pid;

char status;

}sReport;

int len200, len404, len503;

int pipe_fd1[2], pipe_fd2[2];

void process_child(int listenfd, char* filename)

{

int connfd;

int cnt, len;

struct sockaddr_in cliaddr;

socklen_t clilen = sizeof(cliaddr);

sReport req;

char comm = '\0';

int running = 1;

char head_buf[1024];

req.pid = getpid();

while(running)

{

connfd = accept(listenfd, (struct sockaddr *)&cliaddr, &clilen);

if(connfd < 0)

err_sys("accept");

req.status = 'n';

/* send message to parent process that got a new accept */

if(write(pipe_fd1[1], &req, sizeof(req)) < 0)

err_sys("write");

int fd;

struct stat file_stat;

if((fd = open(filename, O_RDONLY)) < 0)

err_sys("open");

if(stat(filename, &file_stat) < 0)

err_sys("stat");

bzero(head_buf, sizeof(head_buf));

len = 0;

cnt = snprintf(head_buf, BUFFSIZE - 1, head200);

len += cnt;

cnt = snprintf(head_buf + len, BUFFSIZE - 1 - len, "Coontent-Length: %lu\r\n", file_stat.st_size);

len += cnt;

cnt = snprintf(head_buf + len, BUFFSIZE - 1 - len, "\r\n");

char *file_buf;

struct iovec iv[2];

if((file_buf = (char *)malloc(file_stat.st_size)) == NULL)

err_sys("malloc");

bzero(file_buf, file_stat.st_size);

if(read(fd, file_buf, file_stat.st_size) < 0)

err_sys("read");

iv[0].iov_base = head_buf;

iv[0].iov_len = strlen(head_buf);

iv[1].iov_base = file_buf;

iv[1].iov_len = strlen(file_buf);

writev(connfd, iv, 2); /* send the file to client host */

free(file_buf);

close(fd);

close(connfd);

req.status = 'f';

/* tell parent process that finish the request */

if(write(pipe_fd1[1], &req, sizeof(req)) < 0)

err_sys("write");

/* wait for commond from parent process */

if(read(pipe_fd2[0], &comm, 1) < 1)

err_sys("read");

if('e' == comm)

{

printf("[%d] exit\n", req.pid);

running = 0;

}

else if('c' == comm)

printf("[%d] continue\n", req.pid);

else

printf("[%d]: comm: %c illeagle\n", req.pid, comm);

}

}

void handle_sigchld(int sig)

{

printf("the child process exit.\n");

}

int main(int argc, char *argv[])

{

int listenfd;

struct sockaddr_in servaddr;

pid_t pid;

if(argc != 2)

err_exit("Usage: http-server port\n");

int port = atoi(argv[1]);

len200 = strlen(head200);

len404 = strlen(head404);

len503 = strlen(head503);

if(signal(SIGCHLD, handle_sigchld) < 0)

err_sys("signal");

if(pipe(pipe_fd1) < 0)

err_sys("pipe pipe_fd1");

if(pipe(pipe_fd2) < 0)

err_sys("pipe piep_fd2");

bzero(&servaddr, sizeof(servaddr));

servaddr.sin_family = AF_INET;

servaddr.sin_port = htons(port);

servaddr.sin_addr.s_addr = htonl(INADDR_ANY);

if((listenfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)

err_sys("socket");

if(bind(listenfd, (struct sockaddr *)&servaddr, sizeof(servaddr)) < 0)

err_sys("bind");

if(listen(listenfd, 10) < 0)

err_sys("listen");

int i;

for(i = 0; i < MAXCHILD; i++)

{

if((pid = fork()) < 0)

err_sys("fork");

else if(0 == pid)

{

process_child(listenfd, "test.txt"); //test.txt为测试文件,内容为 Hello World!!!

}

else

{

printf("have create child %d\n", pid);

}

}

close(pipe_fd1[1]);

close(pipe_fd2[0]);

close(listenfd);

char c = 'c';

int req_num = 0;

sReport req;

while(1)

{

if(read(pipe_fd1[0], &req, sizeof(req)) < 0)

err_sys("read pipe_fd1");

/* a new request come */

if(req.status == 'n') //子进程收到一个连接请求

{

req_num++;

printf("parent: %d have receive new request\n", req.pid);

}

else if(req.status == 'f') /* just finish a accept */

{

req_num--;

if(write(pipe_fd2[1], &c, sizeof(c)) < sizeof(c))

err_sys("write");

}

}

printf("Done\n");

return 0;

}

参考资料:

1、《Linux高性能服务器编程》 第15章 进程池和线程池

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值