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

传统上并发服务器调用fork派生一个子进程来处理每个客户。这使得服务器能够同时为多个客户服务,每个进程一个客户。客户数目的唯一限制是操作系统对以其名义运行服务器的用户ID能够同时有多个子进程的限制。并发服务器的问题在于为每个客户现场fork一个子进程比较耗费CPU时间。

本函数为每个客户连接fork一个子进程并处理来自垂死的子进程的SIGCHLD信号。我们还捕获由键入终端中断按键产生的SIGINT信号。在客户运行完毕之后我们键入该键以显示服务器程序运行所需的CPU时间。下面给出了SIGINT信号处理函数。这是一个信号处理函数不返回而直接终止进程。
       getrusage函数被调用了两次,分别返回调用进程(RUSAGE_SELF)和它的所有已终止子进程(RUSAGE_CHILDREN)的资源利用统计。所显示的值包括总的系统时间(内核在代表调用进程执行系统调用上耗费的CPU时间)。
        客户在建立与服务器的连接之后通过该连接写出一行文本,指出需由服务器发送多少字节的数据给客户。这一点与HTTP有些类似:客户发送一个小请求,服务器响应以所期望的信息(例如一个HTML文件或一副GIF图片),在HTTP应用系统中,服务器通常在发送回所请求的数据之间就关闭连接,不过较新的版本允许使用持续连接,为在某个时限以内到达的额外客户请求继续保持TCP连接开发一段时间。
        在web_child函数中,服务器允许来自客户的额外请求。

#include	"unp.h"
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 sig_int(int signo)
{
void pr_cpu_time(void); pr_cpu_time();
exit(0);
} void sig_chld(int signo)
{
pid_t pid;
int stat; while ( (pid = waitpid(-1, &stat, WNOHANG)) > 0)
printf("child %d terminated\n", pid);
return;
} #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);
}
} int main(int argc, char **argv)
{
int listenfd, connfd;
pid_t childpid;
void sig_chld(int), 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 */
}
}

UNIX网络编程——客户/服务器程序设计示范(二)的更多相关文章

  1. UNIX网络编程——客户/服务器程序设计示范(总结)

    (1)当系统负载较轻是,每来一个客户请求现场派生一个子进程为之服务的传统并发服务器程序模型就足够了.这个模型甚至可以与inetd结合使用,也就是inetd处理每个连接的接收.我们的其他意见是就重负荷运 ...

  2. UNIX网络编程——客户/服务器程序设计示范(八)

        TCP预先创建线程服务器程序,主线程统一accept 最后一个使用线程的服务器程序设计示范是在程序启动阶段创建一个线程池之后只让主线程调用accept并把每个客户连接传递给池中某个可用线程.  ...

  3. UNIX网络编程——客户/服务器程序设计示范(七)

        TCP预先创建线程服务器程序,每个线程各自accept 前面讨论过预先派生一个子进程池快于为每个客户线程派生一个子进程.在支持线程的系统上,我们有理由预期在服务器启动阶段预先创建一个线程池以取 ...

  4. UNIX网络编程——客户/服务器程序设计示范(六)

    TCP并发服务器程序,每个客户一个线程 前面讲述了,每个客户一个进程的服务器,或为每个客户现场fork一个子进程,或者预先派生一定数目的子进程.如果服务器主机支持线程,我们就可以改用线程以取代子进程. ...

  5. UNIX网络编程——客户/服务器程序设计示范(五)

        TCP预先派生子进程服务器程序,传递描述符 对预先派生子进程服务器程序的最后一个修改版本是只让父进程调用accept,然后把所接受的已连接套接字"传递"给某个子进程.这么做 ...

  6. UNIX网络编程——客户/服务器程序设计示范(三)

    TCP预先派生子进程服务器程序,accept无上锁保护 我们的第一个"增强"型服务器程序使用称为预先派生子进程的技术.使用该技术的服务器不像传统意义的并发服务器那样为每个客户现场派 ...

  7. UNIX网络编程——客户/服务器程序设计示范(一)

    下面给出的是客户程序用于测试我们的服务器程序的各个变体. #include "unp.h" #define MAXN 16384 /* max # bytes to request ...

  8. UNIX网络编程——客户/服务器程序设计示范(四)

        TCP预先派生子进程服务器程序,accept使用线程上锁保护 我们使用线程上锁保护accept,因为这种方法不仅适用于同一进程内各线程之间的上锁,而且适用于不同进程之间的上锁.        ...

  9. UNIX网络编程——客户/服务器心搏函数

    阅读此博客时,可以参考以前的博客<<UNIX网络编程--socket的keep-alive>>和<<UNIX网络编程--套接字选项(心跳检测.绑定地址复用)> ...

随机推荐

  1. 使用JAXB解析xml文件(一)

      1.java中解析xml的几种方式 1.1 JDK原生dom形式 原理:一次性把xml读入内存,在内存中构建成树形结构.优点:对节点操作方便,缺点:需要大量的内存空间,浪费资源 1.2 SAX形式 ...

  2. Linux配置服务器的一点总结

    一.Linux初始化服务 首先搞清楚四个概念: 进程:正在运行的程序,有自己独立的内存空间. 线程:是进程的下属单位,开销较进程小,没有自己独立的内存空间. 作业:由一系列进程组成,来完成某一项任务. ...

  3. python webdriver环境搭建

    一.准备安装包 1.下载python 2.下载setuptools 3.下载pip 二.windows环境安装 1.安装python,建议选择python2.7.5版本. 2.安装setuptools ...

  4. C语言实现的排序

    冒泡排序 比较相邻的两个元素,若顺序不对,则将其调换 通过一遍排序,较大的数会排到最后(沉到底部) 两层循环,外层循环控制遍数,内层循环控制每一遍内的排序. 完整代码: #include<std ...

  5. vue项目开发中遇到的问题总结--内部分享

     1.路由变化页面数据不刷新问题 这种情况一般出现在vue-router的history模式下,初次进入会执行钩子函数,再次进入时则不会. 解决方案: 监听路由变化 watch : { "$ ...

  6. AJAX 向后台发送带 List 集合的对象

    现有基类: public class School { int name; int address; List<Student> students = new ArrayList<S ...

  7. SAS中的剔除空格函数

    left函数:         刪除字符串左边(开头> 的空格right函数:       刪除字符串右边(结尾> 的空格trim函数:         刪除字符串右边(结尾> 的空 ...

  8. 在linux系统中I/O 调度的选择

        I/O 调度算法再各个进程竞争磁盘I/O的时候担当了裁判的角色.他要求请求的次序和时机做最优化的处理,以求得尽可能最好的整体I/O性能. 在linux下面列出4种调度算法 CFQ (Compl ...

  9. 安卓高级3 Android应用Design Support Library完全使用实例

    原作者:http://www.open-open.com/lib/view/open1433385856119.html 1 背景 上周一年一度的Google IO全球开发者大会刚刚结束,Google ...

  10. 手把手图文教你从Eclipse项目迁移Android Studio

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52937391 从Android的 ...