根據預定義進程數創建進程池。
父子進程通信使用的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);
}