unix网络编程各种TCP客户-服务器程序设计实例(三)
第五种 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 *);
#endifvoid
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);elseerr_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
转载于:https://www.cnblogs.com/javaspring/archive/2012/08/25/2656202.html
unix网络编程各种TCP客户-服务器程序设计实例(三)相关推荐
- UNIX网络编程——基本TCP套接字编程 【转贴】
一.基于TCP协议的网络程序 下图是基于TCP协议的客户端/服务器程序的一般流程: 服务器调用socket().bind().listen()完成初始化后,调用accept()阻塞等待,处于监听端口的 ...
- UNIX网络编程——UDP回射服务器程序(初级版本)以及漏洞分析
该函数提供的是一个迭代服务器,而不是像TCP服务器那样可以提供一个并发服务器.其中没有对fork的调用,因此单个服务器进程就得处理所有客户.一般来说,大多数TCP服务器是并发的,而大多数UDP服务器是 ...
- 第四章 基本TCP套接字编程 第五章 TCP客户/服务器程序实例
TCP客户与服务器进程之间发生的重大事件时间表 TCP服务器 socket() --- bind() --- listen() --- accept() --- read() --- write -- ...
- UNIX网络编程——解决TCP网络传输“粘包”问题
当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport ...
- 【Unix 网络编程】TCP状态转换图详解
TCP协议的三路握手和四次挥手.如下图所示,TCP通信过程包括三个步骤:建立TCP连接通道(三次握手).数据传输.断开TCP连接通道(四次挥手). 这里进一步探究TCP三路握手和四次挥手过程中的状态变 ...
- Unix网络编程 提高 TCP I/O 性能的3点经验
用John Nagle算法最小化报文传输延时通过 TCP socket 进行通信时,数据都拆分成了数据块,放到一个TCP报文中为了达到最好的性能,总希望尽可能多的可用数据来填充每个报文已达到为最大报文 ...
- 《UNIX网络编程 卷1:套接字联网API》学习笔记——基本TCP套接字编程
UNIX网络编程--基本TCP套接字编程 socket 函数 connect 函数 bind 函数 listen 函数 accept 函数 fork 和 exec 函数 并发服务器 close 函数 ...
- UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式
本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select ...
- Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍
转载:http://blog.csdn.net/michael_kong_nju/article/details/43457393 写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API, ...
最新文章
- 不同浏览器对URL最大长度的限制
- 【Ubuntu入门到精通系列讲解】Linux 终端命令格式
- C++中的类模板详细讲述
- 【专升本计算机】甘肃省普通高等学校专升本考试计算机全真模拟试卷(一)
- 最小生成树——Prim(普利姆)算法
- iphone6php怎么打开,苹果手机中的heic格式文件怎么打开
- jvm 调优 2020.09.07
- visio素材:安防监控visio素材图库
- 三年建模师告诉你3DMAX有没有前途
- kindle电子书转PDF,结合calibre工具和DeDRM_tools使用
- 前端道路上,买书的那些事儿
- ubuntu实现屏幕的旋转和开启自动旋转屏幕
- dos下masm的out of memory 怎么解决,求大佬指教
- Google Earth Engine(GEE)——python法国里昂地区的地表温度和地面高程的静态制图
- windows查看office软件激活信息
- 虚幻5新特性之EnhancedInput
- 电脑崩溃?黑客最爱邮件入侵方式,在双十一也要保护好网络安全!
- debian安装docker
- 浅析android手游lua脚本的加密与解密
- verdi\debussy的使用技巧
热门文章
- 浅谈抖音下拉词框优化推广的优势
- html页面酷炫,5个酷炫、实用的HTML标签和属性介绍
- hibernate oracle 读写分离_ASP.NET CORE 国产最火前后端完全分离框架BCVP
- python装饰器解析请求参数_我如何在装饰器中获得Flask可选的URL参数?
- 机器人煮面机创始人_那个火爆的煮面机器人搬走了!一大波机器人“入侵”,无人餐厅只是玩噱头?...
- oc代码混淆_OC代码混淆工具
- java如何简单的将一个三位正整数分解成三个数
- 直播预告 | Rainbond与Service Mesh微服务架构
- 自己实现的数值到大写人民币的实现
- (hdu step 6.3.3)Air Raid(最小路径覆盖:求用最少边把全部的顶点都覆盖)