UNIX网络编程——客户/服务器程序设计示范(二)
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网络编程——客户/服务器程序设计示范(二)的更多相关文章
- UNIX网络编程——客户/服务器程序设计示范(总结)
(1)当系统负载较轻是,每来一个客户请求现场派生一个子进程为之服务的传统并发服务器程序模型就足够了.这个模型甚至可以与inetd结合使用,也就是inetd处理每个连接的接收.我们的其他意见是就重负荷运 ...
- UNIX网络编程——客户/服务器程序设计示范(八)
TCP预先创建线程服务器程序,主线程统一accept 最后一个使用线程的服务器程序设计示范是在程序启动阶段创建一个线程池之后只让主线程调用accept并把每个客户连接传递给池中某个可用线程. ...
- UNIX网络编程——客户/服务器程序设计示范(七)
TCP预先创建线程服务器程序,每个线程各自accept 前面讨论过预先派生一个子进程池快于为每个客户线程派生一个子进程.在支持线程的系统上,我们有理由预期在服务器启动阶段预先创建一个线程池以取 ...
- UNIX网络编程——客户/服务器程序设计示范(六)
TCP并发服务器程序,每个客户一个线程 前面讲述了,每个客户一个进程的服务器,或为每个客户现场fork一个子进程,或者预先派生一定数目的子进程.如果服务器主机支持线程,我们就可以改用线程以取代子进程. ...
- UNIX网络编程——客户/服务器程序设计示范(五)
TCP预先派生子进程服务器程序,传递描述符 对预先派生子进程服务器程序的最后一个修改版本是只让父进程调用accept,然后把所接受的已连接套接字"传递"给某个子进程.这么做 ...
- UNIX网络编程——客户/服务器程序设计示范(三)
TCP预先派生子进程服务器程序,accept无上锁保护 我们的第一个"增强"型服务器程序使用称为预先派生子进程的技术.使用该技术的服务器不像传统意义的并发服务器那样为每个客户现场派 ...
- UNIX网络编程——客户/服务器程序设计示范(一)
下面给出的是客户程序用于测试我们的服务器程序的各个变体. #include "unp.h" #define MAXN 16384 /* max # bytes to request ...
- UNIX网络编程——客户/服务器程序设计示范(四)
TCP预先派生子进程服务器程序,accept使用线程上锁保护 我们使用线程上锁保护accept,因为这种方法不仅适用于同一进程内各线程之间的上锁,而且适用于不同进程之间的上锁. ...
- UNIX网络编程——客户/服务器心搏函数
阅读此博客时,可以参考以前的博客<<UNIX网络编程--socket的keep-alive>>和<<UNIX网络编程--套接字选项(心跳检测.绑定地址复用)> ...
随机推荐
- 【集训第二天·翻水的老师】--ac自动机+splay树
今天是第二天集训.(其实已经是第三天了,只是昨天并没有机会来写总结,现在补上) 上午大家心情都很愉快,因为老师讲了splay树和ac自动机. 但到了下午,我们的教练竟然跑出去耍了(excuse me? ...
- spring boot新建项目启动报:Unregistering JMX-exposed beans on shutdown
原因为:SpringBoot内置Tomcat没有正常启动,在pom.xml 中添加: <dependency> <groupId>org.springframework.boo ...
- 浙大patB习题的一点总结
嘛嘛,patB的习题已经结束了,这些基本上没有啥特别难的,但还是有几道特别坑爹的题(o(╯□╰)o),还是把这些题的代码打包上传吧.
- selenium常用内容
一.声明浏览器对象 注意点一,Python文件名或者包名不要命名为selenium,会导致无法导入 from selenium import webdriver #webdriver可以认为是浏览器的 ...
- python显示中文出错以及抛出UnicodeDecodeError的处理办法
程序开头粘贴如下代码即可: # -*- coding:utf-8 -*- import sys default_encoding = 'utf-8' if sys.getdefaultencoding ...
- AsyncLocal 与 async await
大家来看一张图 先猜猜看为什么会这样 关于async await的原理 建议查看 https://blog.csdn.net/brook_shi/article/details/50803957 这篇 ...
- 底部导航栏实现一 Fragment-replace
[效果](这里下载的软件收费的试用有水印) [推荐]这里推荐一个图标网http://iconfont.cn/.以上图标来自此图标网 [项目结构] [步骤] ①创建布局文件,写底部导航栏 <?xm ...
- c++ Struct和Class的区别
C++中的struct对C中的struct进行了扩充,它已经不再只是一个包含不同数据类型的数据结构了,它已经获取了太多的功能.struct能包含成员函数吗? 能!struct能继承吗? 能!!stru ...
- Java Spring boot 2.0 跨域问题
跨域 一个资源会发起一个跨域HTTP请求(Cross-site HTTP request), 当它请求的一个资源是从一个与它本身提供的第一个资源的不同的域名时 . 比如说,域名A(http://dom ...
- jQuery 学习笔记一