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 */ } }
相关文章推荐
- TCP并发服务器,每个客户一个子进程
- TCP并发服务器(一)——每个客户一个子进程
- TCP并发服务器,每个客户一个子进程
- TCP并发server,每个客户一个子进程
- TCP并发服务器程序,每个客户一个子进程
- TCP并发服务器程序,每个客户一个子进程
- UNIX网络编程卷1 服务器程序设计范式1 并发服务器,为每个客户请求fork一个进程
- 用NetHogs监控Linux每个进程的网络使用情况
- 实验16-14 请在testdb中:查找每个客户(包括没有订单的客户)的客户
- 同一个父进程的多个子进程之间的通信
- 客户管理系统里的每个模块该如何显示?
- UNIX网络编程卷1 server程序设计范式1 并发server,为每一个客户请求fork一个进程
- 查看Linux每个进程的流量和带宽
- 队列应用银行排队问题模拟:计算客户的平均停留时间和等待时间以及每个客户的时间信息,两种方法实现
- 每个进程有两个栈
- 子进程的信号捕捉函数是否会因为另外一个子进程的结束而被触发
- 如何用 Instruments 检测 iOS 每个进程的电量消耗?
- Linux服务器利用Nethogs监控每个进程的网络使用情况
- linux中fork同时创建多个子进程的方法(二)
- Android入门之在客户进程中注册InputChannel