第五种  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客户-服务器程序设计实例(三)相关推荐

  1. UNIX网络编程——基本TCP套接字编程 【转贴】

    一.基于TCP协议的网络程序 下图是基于TCP协议的客户端/服务器程序的一般流程: 服务器调用socket().bind().listen()完成初始化后,调用accept()阻塞等待,处于监听端口的 ...

  2. UNIX网络编程——UDP回射服务器程序(初级版本)以及漏洞分析

    该函数提供的是一个迭代服务器,而不是像TCP服务器那样可以提供一个并发服务器.其中没有对fork的调用,因此单个服务器进程就得处理所有客户.一般来说,大多数TCP服务器是并发的,而大多数UDP服务器是 ...

  3. 第四章 基本TCP套接字编程 第五章 TCP客户/服务器程序实例

    TCP客户与服务器进程之间发生的重大事件时间表 TCP服务器 socket() --- bind() --- listen() --- accept() --- read() --- write -- ...

  4. UNIX网络编程——解决TCP网络传输“粘包”问题

           当前在网络传输应用中,广泛采用的是TCP/IP通信协议及其标准的socket应用开发编程接口(API).TCP/IP传输层有两个并列的协议:TCP和UDP.其中TCP(transport ...

  5. 【Unix 网络编程】TCP状态转换图详解

    TCP协议的三路握手和四次挥手.如下图所示,TCP通信过程包括三个步骤:建立TCP连接通道(三次握手).数据传输.断开TCP连接通道(四次挥手). 这里进一步探究TCP三路握手和四次挥手过程中的状态变 ...

  6. Unix网络编程 提高 TCP I/O 性能的3点经验

    用John Nagle算法最小化报文传输延时通过 TCP socket 进行通信时,数据都拆分成了数据块,放到一个TCP报文中为了达到最好的性能,总希望尽可能多的可用数据来填充每个报文已达到为最大报文 ...

  7. 《UNIX网络编程 卷1:套接字联网API》学习笔记——基本TCP套接字编程

    UNIX网络编程--基本TCP套接字编程 socket 函数 connect 函数 bind 函数 listen 函数 accept 函数 fork 和 exec 函数 并发服务器 close 函数 ...

  8. UNIX网络编程卷1 回射客户程序 TCP客户程序设计范式

    本文为senlie原创,转载请保留此地址:http://blog.csdn.net/zhengsenlie 下面我会介绍同一个使用 TCP 协议的客户端程序的几个不同版本,分别是停等版本.select ...

  9. Unix 网络编程(四)- 典型TCP客服服务器程序开发实例及基本套接字API介绍

    转载:http://blog.csdn.net/michael_kong_nju/article/details/43457393 写在开头: 在上一节中我们学习了一些基础的用来支持网络编程的API, ...

最新文章

  1. 不同浏览器对URL最大长度的限制
  2. 【Ubuntu入门到精通系列讲解】Linux 终端命令格式
  3. C++中的类模板详细讲述
  4. 【专升本计算机】甘肃省普通高等学校专升本考试计算机全真模拟试卷(一)
  5. 最小生成树——Prim(普利姆)算法
  6. iphone6php怎么打开,苹果手机中的heic格式文件怎么打开
  7. jvm 调优 2020.09.07
  8. visio素材:安防监控visio素材图库
  9. 三年建模师告诉你3DMAX有没有前途
  10. kindle电子书转PDF,结合calibre工具和DeDRM_tools使用
  11. 前端道路上,买书的那些事儿
  12. ubuntu实现屏幕的旋转和开启自动旋转屏幕
  13. dos下masm的out of memory 怎么解决,求大佬指教
  14. Google Earth Engine(GEE)——python法国里昂地区的地表温度和地面高程的静态制图
  15. windows查看office软件激活信息
  16. 虚幻5新特性之EnhancedInput
  17. 电脑崩溃?黑客最爱邮件入侵方式,在双十一也要保护好网络安全!
  18. debian安装docker
  19. 浅析android手游lua脚本的加密与解密
  20. verdi\debussy的使用技巧

热门文章

  1. 浅谈抖音下拉词框优化推广的优势
  2. html页面酷炫,5个酷炫、实用的HTML标签和属性介绍
  3. hibernate oracle 读写分离_ASP.NET CORE 国产最火前后端完全分离框架BCVP
  4. python装饰器解析请求参数_我如何在装饰器中获得Flask可选的URL参数?
  5. 机器人煮面机创始人_那个火爆的煮面机器人搬走了!一大波机器人“入侵”,无人餐厅只是玩噱头?...
  6. oc代码混淆_OC代码混淆工具
  7. java如何简单的将一个三位正整数分解成三个数
  8. 直播预告 | Rainbond与Service Mesh微服务架构
  9. 自己实现的数值到大写人民币的实现
  10. (hdu step 6.3.3)Air Raid(最小路径覆盖:求用最少边把全部的顶点都覆盖)