您的位置:首页 > 理论基础 > 计算机网络

unix网络编程各种TCP客户-服务器程序设计实例(三)

2012-08-25 10:06 302 查看
第五种 TCP预先派生子进程服务器程序:

对预先派生子进程服务器的最后一种改动就是由父进程调用accept,然后再将所接受的已连接描述字传递给子进程。父进程必须跟踪子进程的忙闲状态,以便给空闲子进程传递新的描述字。为每个子进程维护一个信息结构,用来管理各子进程。



在调用fork之前,先创建一个字节流管道(Unix域的字节流套接口),它是Unix域的字节流套接口。当子进程派生后,父进程关闭一个描述字(sockfd[1]),子进程关闭另一个描述字(sockfd[0]),此外,子进程将流管道的字节所在端(sockfd[1])复制到标准输出。



child.h:

typedef struct {
pid_t		child_pid;		/* process ID */
int		child_pipefd;	/* parent's stream pipe to/from child */
int		child_status;	/* 0 = ready */
long		child_count;	/* # connections handled */
} Child;

Child	*cptr;		/* array of Child structures; calloc'ed */

Child.c:

/* include child_make */
#include	"unp.h"
#include	"child.h"

Child	*cptr;		/* array of Child structures; calloc'ed */
pid_t
child_make(int i, int listenfd, int addrlen)
{
int		sockfd[2];
pid_t	pid;
void	child_main(int, int, int);

Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);

if ( (pid = Fork()) > 0) {
Close(sockfd[1]);
cptr[i].child_pid = pid;
cptr[i].child_pipefd = sockfd[0];
cptr[i].child_status = 0;
return(pid);		/* parent */
}

Dup2(sockfd[1], STDERR_FILENO);		/* child's stream pipe to parent */
Close(sockfd[0]);
Close(sockfd[1]);
Close(listenfd);					/* child does not need this open */
child_main(i, listenfd, addrlen);	/* never returns */
}
/* end child_make */

/* include child_main */
void
child_main(int i, int listenfd, int addrlen)
{
char			c;
int				connfd;
ssize_t			n;
void			web_child(int);

printf("child %ld starting\n", (long) getpid());
for ( ; ; ) {
if ( (n = Read_fd(STDERR_FILENO, &c, 1, &connfd)) == 0)
err_quit("read_fd returned 0");
if (connfd < 0)
err_quit("no descriptor from read_fd");

web_child(connfd);				/* process request */
Close(connfd);

Write(STDERR_FILENO, "", 1);	/* tell parent we're ready again */
}
}
/* end child_main */

pr_cpu_time.c:

#include	"unp.h"
#include	<sys/resource.h>

#ifndef	HAVE_GETRUSAGE_PROTO
int		getrusage(int, struct rusage *);
#endif

void
pr_cpu_time(void)
{
double			user, sys;
struct rusage	myusage, childusage;

if (getrusage(RUSAGE_SELF, &myusage) < 0)
err_sys("getrusage error");
if (getrusage(RUSAGE_CHILDREN, &childusage) < 0)
err_sys("getrusage error");

user = (double) myusage.ru_utime.tv_sec +
myusage.ru_utime.tv_usec/1000000.0;
user += (double) childusage.ru_utime.tv_sec +
childusage.ru_utime.tv_usec/1000000.0;
sys = (double) myusage.ru_stime.tv_sec +
myusage.ru_stime.tv_usec/1000000.0;
sys += (double) childusage.ru_stime.tv_sec +
childusage.ru_stime.tv_usec/1000000.0;

printf("\nuser time = %g, sys time = %g\n", user, sys);
}

web_child.c:

#include	"unp.h"

#define	MAXN	16384		/* max # bytes client can request */

void
web_child(int sockfd)
{
int			ntowrite;
ssize_t		nread;
char		line[MAXLINE], result[MAXN];

for ( ; ; ) {
if ( (nread = Readline(sockfd, line, MAXLINE)) == 0)
return;		/* connection closed by other end */

/* 4line from client specifies #bytes to write back */
ntowrite = atol(line);
if ((ntowrite <= 0) || (ntowrite > MAXN))
err_quit("client request for %d bytes", ntowrite);

Writen(sockfd, result, ntowrite);
}
}


client.c:

#include	"unp.h"

#define	MAXN	16384		/* max # bytes to request from server */

int
main(int argc, char **argv)
{
int		i, j, fd, nchildren, nloops, nbytes;
pid_t	pid;
ssize_t	n;
char	request[MAXLINE], reply[MAXN];

if (argc != 6)
err_quit("usage: client <hostname or IPaddr> <port> <#children> "
"<#loops/child> <#bytes/request>");

nchildren = atoi(argv[3]);
nloops = atoi(argv[4]);
nbytes = atoi(argv[5]);
snprintf(request, sizeof(request), "%d\n", nbytes); /* newline at end */

for (i = 0; i < nchildren; i++) {
if ( (pid = Fork()) == 0) {		/* child */
for (j = 0; j < nloops; j++) {
fd = Tcp_connect(argv[1], argv[2]);

Write(fd, request, strlen(request));

if ( (n = Readn(fd, reply, nbytes)) != nbytes)
err_quit("server returned %d bytes", n);

Close(fd);		/* TIME_WAIT on client, not server */
}
printf("child %d done\n", i);
exit(0);
}
/* parent loops around to fork() again */
}

while (wait(NULL) > 0)	/* now parent waits for all children */
;
if (errno != ECHILD)
err_sys("wait error");

exit(0);
}

server.c:

/* include serv05a */
#include	"unp.h"
#include	"child.h"

static int		nchildren;

int
main(int argc, char **argv)
{
int			listenfd, i, navail, maxfd, nsel, connfd, rc;
void		sig_int(int);
pid_t		child_make(int, int, int);
ssize_t		n;
fd_set		rset, masterset;
socklen_t	addrlen, clilen;
struct sockaddr	*cliaddr;

if (argc == 3)
listenfd = Tcp_listen(NULL, argv[1], &addrlen);
else if (argc == 4)
listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
else
err_quit("usage: serv05 [ <host> ] <port#> <#children>");

FD_ZERO(&masterset);
FD_SET(listenfd, &masterset);
maxfd = listenfd;
cliaddr = Malloc(addrlen);

nchildren = atoi(argv[argc-1]);
navail = nchildren;
cptr = Calloc(nchildren, sizeof(Child));

/* 4prefork all the children */
for (i = 0; i < nchildren; i++) {
child_make(i, listenfd, addrlen);	/* parent returns */
FD_SET(cptr[i].child_pipefd, &masterset);
maxfd = max(maxfd, cptr[i].child_pipefd);
}

Signal(SIGINT, sig_int);

for ( ; ; ) {
rset = masterset;
if (navail <= 0)
FD_CLR(listenfd, &rset);	/* turn off if no available children */
nsel = Select(maxfd + 1, &rset, NULL, NULL, NULL);

/* 4check for new connections */
if (FD_ISSET(listenfd, &rset)) {
clilen = addrlen;
connfd = Accept(listenfd, cliaddr, &clilen);

for (i = 0; i < nchildren; i++)
if (cptr[i].child_status == 0)
break;				/* available */

if (i == nchildren)
err_quit("no available children");
cptr[i].child_status = 1;	/* mark child as busy */
cptr[i].child_count++;
navail--;

n = Write_fd(cptr[i].child_pipefd, "", 1, connfd);
Close(connfd);
if (--nsel == 0)
continue;	/* all done with select() results */
}

/* 4find any newly-available children */
for (i = 0; i < nchildren; i++) {
if (FD_ISSET(cptr[i].child_pipefd, &rset)) {
if ( (n = Read(cptr[i].child_pipefd, &rc, 1)) == 0)
err_quit("child %d terminated unexpectedly", i);
cptr[i].child_status = 0;
navail++;
if (--nsel == 0)
break;	/* all done with select() results */
}
}
}
}
/* end serv05a */

void
sig_int(int signo)
{
int		i;
void	pr_cpu_time(void);

/* 4terminate all children */
for (i = 0; i < nchildren; i++)
kill(cptr[i].child_pid, SIGTERM);
while (wait(NULL) > 0)		/* wait for all children */
;
if (errno != ECHILD)
err_sys("wait error");

pr_cpu_time();

for (i = 0; i < nchildren; i++)
printf("child %d, %ld connections\n", i, cptr[i].child_count);

exit(0);
}

编译命令:

gcc server.c child.c pr_cpu_time.c web_child.c -o server -lunp
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: