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

TCP并发服务器程序,每个客户一个子进程

2017-07-20 10:13 429 查看
TCP并发服务器程序,每个客户一个子进程

#define _GNU_SOURCE
#include    <sys/wait.h>
#include    <signal.h>
#include    <unistd.h>
#include    <string.h>
#include    <stdio.h>
#include    <errno.h>
#include    <strings.h>
#include    <stdlib.h>
#include    <sys/socket.h>
#include    <sys/types.h>
#include    <netdb.h>
#include    <syslog.h>
#include    <stdarg.h>
#include    <sys/resource.h>
#define LISTENQ     1024    /* 2nd argument to listen() */
#define MAXLINE     4096    /* max text line length */
#define MAXN    16384       /* max # bytes to request from server */
typedef void Sigfunc(int);  /* for signal handlers */
int daemon_proc;        /* set nonzero by daemon_init() */

void sig_int(int signo)//ctrl-c 信号处理函数
{
void pr_cpu_time(void);

pr_cpu_time();
exit(0);
}

void err_doit(int errnoflag, int level, const char *fmt, va_list ap)
{
int errno_save, n;
char buf[MAXLINE + 1];

errno_save = errno; /* value caller might want printed */
#ifdef  HAVE_VSNPRINTF
vsnprintf(buf, MAXLINE, fmt, ap);   /* safe */
#else
vsprintf(buf, fmt, ap); /* not safe */
#endif
n = strlen(buf);
if (errnoflag)
snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
strcat(buf, "\n");

if (daemon_proc) {
syslog(level, "%s", buf);
} else {
fflush(stdout); /* in case stdout and stderr are the same */
fputs(buf, stderr);
fflush(stderr);
}
return;
}

void err_quit(const char *fmt, ...)
{
va_list ap;

va_start(ap, fmt);
err_doit(0, LOG_ERR, fmt, ap);
va_end(ap);
exit(1);
}

void err_sys(const char *fmt, ...)
{
va_list ap;

va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, ap);
va_end(ap);
exit(1);
}

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);
}
//设置套接字选项
void Setsockopt(int fd, int level, int optname, const void *optval,
socklen_t optlen)
{
if (setsockopt(fd, level, optname, optval, optlen) < 0)
err_sys("setsockopt error");
}

void Close(int fd)
{
if (close(fd) == -1)
err_sys("close error");
}

void Listen(int fd, int backlog)
{
char *ptr;

/*4can override 2nd argument with environment variable */
if ((ptr = getenv("LISTENQ")) != NULL)
backlog = atoi(ptr);

if (listen(fd, backlog) < 0)
err_sys("listen error");
}

int tcp_listen(const char *host, const char *serv, socklen_t * addrlenp)
{
int listenfd, n;
const int on = 1;
struct addrinfo hints, *res, *ressave;

bzero(&hints, sizeof(struct addrinfo));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

if ((n = getaddrinfo(host, serv, &hints, &res)) != 0)
err_quit("tcp_listen error for %s, %s: %s",
host, serv, gai_strerror(n));
ressave = res;

do {
listenfd =
socket(res->ai_family, res->ai_socktype, res->ai_protocol);
if (listenfd < 0)
continue;   /* error, try next one */

Setsockopt(listenfd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
if (bind(listenfd, res->ai_addr, res->ai_addrlen) == 0)
break;  /* success */

Close(listenfd);    /* bind error, close and try next one */
} while ((res = res->ai_next) != NULL);

if (res == NULL)    /* errno from final socket() or bind() */
err_sys("tcp_listen error for %s, %s", host, serv);

Listen(listenfd, LISTENQ);

if (addrlenp)
*addrlenp = res->ai_addrlen; /* return size of protocol address */

freeaddrinfo(ressave);

return (listenfd);
}
//执行TCP服务器的通常步骤 socket,bind,listen,
int Tcp_listen(const char *host, const char *serv, socklen_t * addrlenp)
{
return (tcp_listen(host, serv, addrlenp));
}

void *Malloc(size_t size)
{
void *ptr;

if ((ptr = malloc(size)) == NULL)
err_sys("malloc error");
return (ptr);
}

Sigfunc *signal(int signo, Sigfunc * func)
{
struct sigaction act, oact;

act.sa_handler = func;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
if (signo == SIGALRM) {
#ifdef  SA_INTERRUPT
act.sa_flags |= SA_INTERRUPT;   /* SunOS 4.x */
#endif
} else {
#ifdef  SA_RESTART
act.sa_flags |= SA_RESTART; /* SVR4, 44BSD */
#endif
}
if (sigaction(signo, &act, &oact) < 0)
return (SIG_ERR);
return (oact.sa_handler);
}

Sigfunc *Signal(int signo, Sigfunc * func)
{               /* for our signal() function */
Sigfunc *sigfunc;

if ((sigfunc = signal(signo, func)) == SIG_ERR)
err_sys("signal error");
return (sigfunc);
}

static int read_cnt;
static char *read_ptr;
static char read_buf[MAXLINE];
static ssize_t my_read(int fd, char *ptr)
{

if (read_cnt <= 0) {
again:
if ((read_cnt = read(fd, read_buf, sizeof(read_buf))) < 0) {
if (errno == EINTR)
goto again;
return (-1);
} else if (read_cnt == 0)
return (0);
read_ptr = read_buf;
}

read_cnt--;
*ptr = *read_ptr++;
return (1);
}

ssize_t readline(int fd, void *vptr, int maxlen)
{
ssize_t n, rc;
char c, *ptr;

ptr = vptr;
for (n = 1; n < maxlen; n++) {
if ((rc = my_read(fd, &c)) == 1) {
*ptr++ = c;
if (c == '\n')
break;  /* newline is stored, like fgets() */
} else if (rc == 0) {
*ptr = 0;
return (n - 1); /* EOF, n - 1 bytes were read */
} else
return (-1);    /* error, errno set by read() */
}

*ptr = 0;       /* null terminate like fgets() */
return (n);
}

ssize_t Readline(int fd, void *ptr, size_t maxlen)
{
ssize_t n;

if ((n = readline(fd, ptr, maxlen)) < 0)
err_sys("readline error");
return (n);
}

ssize_t             /* Write "n" bytes to a descriptor. */
writen(int fd, const void *vptr, size_t n)
{
size_t nleft;
ssize_t nwritten;
const char *ptr;

ptr = vptr;
nleft = n;
while (nleft > 0) {
if ((nwritten = write(fd, ptr, nleft)) <= 0) {
if (nwritten < 0 && errno == EINTR)
nwritten = 0;   /* and call write() again */
else
return (-1);    /* error */
}

nleft -= nwritten;
ptr += nwritten;
}
return (n);
}

void Writen(int fd, void *ptr, int nbytes)
{
if (writen(fd, ptr, nbytes) != nbytes)
err_sys("writen error");
}
//过程处理函数
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);
}
}

pid_t Fork(void)
{
pid_t pid;

if ((pid = fork()) == -1)
err_sys("fork error");
return (pid);
}
//进程终止
void sig_chld(int signo)
{
pid_t pid;
int stat;

while ((pid = waitpid(-1, &stat, WNOHANG)) > 0) {
printf("child %d terminated\n", pid);
}
return;
}

int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
void sig_chld(int
9202
), sig_int(int), web_child(int);
socklen_t clilen, addrlen;
struct sockaddr *cliaddr;

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

Signal(SIGCHLD, sig_chld);
Signal(SIGINT, sig_int);

for (;;) {
clilen = addrlen;
if ((connfd = accept(listenfd, cliaddr, &clilen)) < 0) {
if (errno == EINTR)
continue;   /* back to for() */
else
err_sys("accept error");
}

if ((childpid = Fork()) == 0) { /* child process */
Close(listenfd);    /* close listening socket */
web_child(connfd);  /* process request */
exit(0);
}
Close(connfd);  /* parent closes connected socket */
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: