根据预定义进程数创建进程池。
父子进程通信使用的IPC方式为:UNIX域套接字
父进程listen,aeecpt,并将连接套接字发送到子进程,交由子进程处理该连接。
子进程处理完毕,与父进程通信,实现资源回收,并在下一连接到来交由该完毕的子进程。
#include "unp.h"
#include <assert.h>
#define IDLE 0
#define BUSY 1
#define END 2
typedef struct pro {
pid_t id; /*进程的进程ID*/
int fd; /*与父进程通信的描述符*/
int flags; /*进程当前状态*/
int cnt; /*进程服务的次数*/
}process;
process *mypid; /*进程池*/
ssize_t write__the_fd(int fd, void *ptr, size_t nbytes, int sendfd);
pid_t make_child( int i, int listenfd );
ssize_t read_the_fd(int fd, void *ptr, size_t nbytes, int *recvfd);
void child_func( void);
void clr(int signo);
int main( int argc, char **argv ) {
int nchild, fdmax, listenfd, connfd, i, len, nselect;
char c;
struct sockaddr_in addr, clientaddr;
signal(SIGCHLD, clr);
signal(SIGINT, clr);
fd_set rset, oset;
if(argc != 2)
err_quit("args");
listenfd = socket( AF_INET, SOCK_STREAM, 0 );/*服务器监听套接字*/
if( listenfd < 0 ) {
err_sys("socket");
}
nchild = atoi(argv[1]);
mypid = (struct pro *)malloc( nchild * sizeof( struct pro) );
bzero( &addr, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(SERV_PORT);
addr.sin_addr.s_addr = htonl(INADDR_ANY);
bind(listenfd, (SA *)&addr, sizeof(struct sockaddr));
fdmax = listenfd; /*用于select */
for( i = 0; i < nchild; i++ ) {
make_child(i, listenfd); /*创建子进程并等待给客户服务*/
} /*传入listenfd子进程关闭监听套接字*/
int idle = nchild; /*当前空闲的子进程*/
len = sizeof(struct sockaddr);
FD_ZERO(&oset);
FD_ZERO(&rset);
listen(listenfd,5);
FD_SET(listenfd, &oset);
for( ; ;) {
if(idle == 0)
FD_CLR(listenfd, &oset); /*若没有空闲子进程,则禁止accept新连接*/
else
FD_SET(listenfd, &oset);
rset = oset;
nselect = select(fdmax+1, &rset, NULL, NULL, NULL);
if( FD_ISSET(listenfd, &rset) ) { /*收到客户端连接请求*/
connfd = accept(listenfd, (SA *)&clientaddr, &len);
for( i = 0; i < nchild; i++) {
if(mypid[i].flags == IDLE) { /*查找可供服务的子进程*/
break;
}
}
/* */
assert(i < nchild);
/* */
//connfd = accept(listenfd, (SA *)&clientaddr, &len);
printf("the id is %d \n",i);
mypid[i].flags = BUSY; /*改变子进程状态*/
mypid[i].cnt ++; /*子进程服务次数*/
FD_SET(mypid[i].fd, &oset); /*加入描述集,等待子进程*/
fdmax = max(fdmax ,mypid[i].fd);
idle --; /*空闲进程减少*/
/*通知子进程*/
write_the_fd(mypid[i].fd, " ", 1,connfd);/*把连接套接字传送给子进程*/
close(connfd); /*因为有有一个confd在飞,所以这个可以关闭*/
if(--nselect ==0)
continue;
}
else {
for(i = 0; i < nchild; i++ ) {
if(FD_ISSET(mypid[i].fd , &rset)) {
read(mypid[i].fd, &c, 1);
mypid[i].flags = IDLE;
FD_CLR(mypid[i].fd, &oset);
idle ++;
}
if(--nselect == 0)
break;
}
}
}
}
void clr(int signo) {
pid_t pid;
while( (pid = waitpid(-1, NULL, WNOHANG)) > 0 ) {
printf("The child %d is done\n", pid);
}
sleep(2);
kill(getpid(), SIGTERM);
return;
}
pid_t make_child( int i, int listenfd ) {
pid_t child;
int fd[2];
socketpair( AF_LOCAL, SOCK_STREAM,0, fd);
if( (child = fork( ) ) < 0 ) {
err_quit("fork ");
}
if( child > 0 ) { /*父进程*/
//printf("the i is %d\n", i);
close( fd[1] );
mypid[i].id = child;
mypid[i].fd= fd[0];
mypid[i].flags = IDLE;
mypid[i].cnt = 0;
return child;
}
/*子进程*/
close( fd[0] );
close(listenfd);
dup2( fd[1], STDERR_FILENO);
close( fd[1]);
child_func();
}
void child_func( void) {
int connfd, n;
char c;
char buf[MAXLINE];
for( ; ; ) {
n = read_fd(STDERR_FILENO, &c, 1, &connfd);
if(n <0 )
err_sys("read_fd");
again:
while( (n = read(connfd, buf, sizeof(buf))) > 0 ){
writen(connfd, buf ,n);
}
if((n < 0)&&( errno == EINTR))
goto again;
else if(n < 0)
err_sys("error");
else if(n ==0) {
close(connfd);
write(STDERR_FILENO, " ", 1);
}
}
}
ssize_t write_the_fd(int fd, void *ptr, size_t nbytes, int sendfd) {
struct msghdr msg;
struct iovec iov[1];
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
cmptr = CMSG_FIRSTHDR(&msg);
cmptr->cmsg_len = CMSG_LEN(sizeof(int));
cmptr->cmsg_level = SOL_SOCKET;
cmptr->cmsg_type = SCM_RIGHTS;
*((int *) CMSG_DATA(cmptr)) = sendfd;
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
return(sendmsg(fd, &msg, 0));
}
ssize_t read_the_fd(int fd, void *ptr, size_t nbytes, int *recvfd) {
struct msghdr msg;
struct iovec iov[1];
ssize_t n;
int newfd;
union {
struct cmsghdr cm;
char control[CMSG_SPACE(sizeof(int))];
} control_un;
struct cmsghdr *cmptr;
msg.msg_control = control_un.control;
msg.msg_controllen = sizeof(control_un.control);
msg.msg_name = NULL;
msg.msg_namelen = 0;
iov[0].iov_base = ptr;
iov[0].iov_len = nbytes;
msg.msg_iov = iov;
msg.msg_iovlen = 1;
if ( (n = recvmsg(fd, &msg, 0)) <= 0)
return(n);
if ( (cmptr = CMSG_FIRSTHDR(&msg)) != NULL &&
cmptr->cmsg_len == CMSG_LEN(sizeof(int))) {
if (cmptr->cmsg_level != SOL_SOCKET)
err_quit("control level != SOL_SOCKET");
if (cmptr->cmsg_type != SCM_RIGHTS)
err_quit("control type != SCM_RIGHTS");
*recvfd = *((int *) CMSG_DATA(cmptr));
} else
*recvfd = -1;
return(n);
}
本文介绍了一个使用UNIX域套接字进行父子进程通信的进程池模型。父进程监听并接受客户端连接,然后通过进程池中的子进程处理这些连接。子进程处理完请求后,会与父进程通信以便资源回收。
7382

被折叠的 条评论
为什么被折叠?



