unix网络编程各种TCP客户-服务器程序设计实例(三)

第五种  TCP预先派生子进程服务器程序:

对预先派生子进程服务器的最后一种改动就是由父进程调用accept,然后再将所接受的已连接描述字传递给子进程。父进程必须跟踪子进程的忙闲状态,以便给空闲子进程传递新的描述字。为每个子进程维护一个信息结构,用来管理各子进程。

在调用fork之前,先创建一个字节流管道(Unix域的字节流套接口),它是Unix域的字节流套接口。当子进程派生后,父进程关闭一个描述字(sockfd[1]),子进程关闭另一个描述字(sockfd[0]),此外,子进程将流管道的字节所在端(sockfd[1])复制到标准输出。

child.h:

  1. typedef struct {
  2. pid_t     child_pid;      /* process ID */
  3. int       child_pipefd;   /* parent‘s stream pipe to/from child */
  4. int       child_status;   /* 0 = ready */
  5. long      child_count;    /* # connections handled */
  6. } Child;
  7. Child   *cptr;      /* array of Child structures; calloc‘ed */

Child.c:

  1. /* include child_make */
  2. #include    "unp.h"
  3. #include    "child.h"
  4. Child   *cptr;      /* array of Child structures; calloc‘ed */
  5. pid_t
  6. child_make(int i, int listenfd, int addrlen)
  7. {
  8. int     sockfd[2];
  9. pid_t   pid;
  10. void    child_main(int, int, int);
  11. Socketpair(AF_LOCAL, SOCK_STREAM, 0, sockfd);
  12. if ( (pid = Fork()) > 0) {
  13. Close(sockfd[1]);
  14. cptr[i].child_pid = pid;
  15. cptr[i].child_pipefd = sockfd[0];
  16. cptr[i].child_status = 0;
  17. return(pid);        /* parent */
  18. }
  19. Dup2(sockfd[1], STDERR_FILENO);     /* child‘s stream pipe to parent */
  20. Close(sockfd[0]);
  21. Close(sockfd[1]);
  22. Close(listenfd);                    /* child does not need this open */
  23. child_main(i, listenfd, addrlen);   /* never returns */
  24. }
  25. /* end child_make */
  26. /* include child_main */
  27. void
  28. child_main(int i, int listenfd, int addrlen)
  29. {
  30. char            c;
  31. int             connfd;
  32. ssize_t         n;
  33. void            web_child(int);
  34. printf("child %ld starting\n", (long) getpid());
  35. for ( ; ; ) {
  36. if ( (n = Read_fd(STDERR_FILENO, &c, 1, &connfd)) == 0)
  37. err_quit("read_fd returned 0");
  38. if (connfd < 0)
  39. err_quit("no descriptor from read_fd");
  40. web_child(connfd);              /* process request */
  41. Close(connfd);
  42. Write(STDERR_FILENO, "", 1);    /* tell parent we‘re ready again */
  43. }
  44. }
  45. /* end child_main */

pr_cpu_time.c:

  1. #include    "unp.h"
  2. #include    <sys/resource.h>
  3. #ifndef HAVE_GETRUSAGE_PROTO
  4. int     getrusage(int, struct rusage *);
  5. #endif
  6. void
  7. pr_cpu_time(void)
  8. {
  9. double          user, sys;
  10. struct rusage   myusage, childusage;
  11. if (getrusage(RUSAGE_SELF, &myusage) < 0)
  12. err_sys("getrusage error");
  13. if (getrusage(RUSAGE_CHILDREN, &childusage) < 0)
  14. err_sys("getrusage error");
  15. user = (double) myusage.ru_utime.tv_sec +
  16. myusage.ru_utime.tv_usec/1000000.0;
  17. user += (double) childusage.ru_utime.tv_sec +
  18. childusage.ru_utime.tv_usec/1000000.0;
  19. sys = (double) myusage.ru_stime.tv_sec +
  20. myusage.ru_stime.tv_usec/1000000.0;
  21. sys += (double) childusage.ru_stime.tv_sec +
  22. childusage.ru_stime.tv_usec/1000000.0;
  23. printf("\nuser time = %g, sys time = %g\n", user, sys);
  24. }

web_child.c:

  1. #include    "unp.h"
  2. #define MAXN    16384       /* max # bytes client can request */
  3. void
  4. web_child(int sockfd)
  5. {
  6. int         ntowrite;
  7. ssize_t     nread;
  8. char        line[MAXLINE], result[MAXN];
  9. for ( ; ; ) {
  10. if ( (nread = Readline(sockfd, line, MAXLINE)) == 0)
  11. return;     /* connection closed by other end */
  12. /* 4line from client specifies #bytes to write back */
  13. ntowrite = atol(line);
  14. if ((ntowrite <= 0) || (ntowrite > MAXN))
  15. err_quit("client request for %d bytes", ntowrite);
  16. Writen(sockfd, result, ntowrite);
  17. }
  18. }

client.c:

  1. #include    "unp.h"
  2. #define MAXN    16384       /* max # bytes to request from server */
  3. int
  4. main(int argc, char **argv)
  5. {
  6. int     i, j, fd, nchildren, nloops, nbytes;
  7. pid_t   pid;
  8. ssize_t n;
  9. char    request[MAXLINE], reply[MAXN];
  10. if (argc != 6)
  11. err_quit("usage: client <hostname or IPaddr> <port> <#children> "
  12. "<#loops/child> <#bytes/request>");
  13. nchildren = atoi(argv[3]);
  14. nloops = atoi(argv[4]);
  15. nbytes = atoi(argv[5]);
  16. snprintf(request, sizeof(request), "%d\n", nbytes); /* newline at end */
  17. for (i = 0; i < nchildren; i++) {
  18. if ( (pid = Fork()) == 0) {     /* child */
  19. for (j = 0; j < nloops; j++) {
  20. fd = Tcp_connect(argv[1], argv[2]);
  21. Write(fd, request, strlen(request));
  22. if ( (n = Readn(fd, reply, nbytes)) != nbytes)
  23. err_quit("server returned %d bytes", n);
  24. Close(fd);      /* TIME_WAIT on client, not server */
  25. }
  26. printf("child %d done\n", i);
  27. exit(0);
  28. }
  29. /* parent loops around to fork() again */
  30. }
  31. while (wait(NULL) > 0)   /* now parent waits for all children */
  32. ;
  33. if (errno != ECHILD)
  34. err_sys("wait error");
  35. exit(0);
  36. }

server.c:

  1. /* include serv05a */
  2. #include    "unp.h"
  3. #include    "child.h"
  4. static int      nchildren;
  5. int
  6. main(int argc, char **argv)
  7. {
  8. int         listenfd, i, navail, maxfd, nsel, connfd, rc;
  9. void        sig_int(int);
  10. pid_t       child_make(int, int, int);
  11. ssize_t     n;
  12. fd_set      rset, masterset;
  13. socklen_t   addrlen, clilen;
  14. struct sockaddr *cliaddr;
  15. if (argc == 3)
  16. listenfd = Tcp_listen(NULL, argv[1], &addrlen);
  17. else if (argc == 4)
  18. listenfd = Tcp_listen(argv[1], argv[2], &addrlen);
  19. else
  20. err_quit("usage: serv05 [ <host> ] <port#> <#children>");
  21. FD_ZERO(&masterset);
  22. FD_SET(listenfd, &masterset);
  23. maxfd = listenfd;
  24. cliaddr = Malloc(addrlen);
  25. nchildren = atoi(argv[argc-1]);
  26. navail = nchildren;
  27. cptr = Calloc(nchildren, sizeof(Child));
  28. /* 4prefork all the children */
  29. for (i = 0; i < nchildren; i++) {
  30. child_make(i, listenfd, addrlen);   /* parent returns */
  31. FD_SET(cptr[i].child_pipefd, &masterset);
  32. maxfd = max(maxfd, cptr[i].child_pipefd);
  33. }
  34. Signal(SIGINT, sig_int);
  35. for ( ; ; ) {
  36. rset = masterset;
  37. if (navail <= 0)
  38. FD_CLR(listenfd, &rset);    /* turn off if no available children */
  39. nsel = Select(maxfd + 1, &rset, NULL, NULL, NULL);
  40. /* 4check for new connections */
  41. if (FD_ISSET(listenfd, &rset)) {
  42. clilen = addrlen;
  43. connfd = Accept(listenfd, cliaddr, &clilen);
  44. for (i = 0; i < nchildren; i++)
  45. if (cptr[i].child_status == 0)
  46. break;              /* available */
  47. if (i == nchildren)
  48. err_quit("no available children");
  49. cptr[i].child_status = 1;   /* mark child as busy */
  50. cptr[i].child_count++;
  51. navail--;
  52. n = Write_fd(cptr[i].child_pipefd, "", 1, connfd);
  53. Close(connfd);
  54. if (--nsel == 0)
  55. continue;   /* all done with select() results */
  56. }
  57. /* 4find any newly-available children */
  58. for (i = 0; i < nchildren; i++) {
  59. if (FD_ISSET(cptr[i].child_pipefd, &rset)) {
  60. if ( (n = Read(cptr[i].child_pipefd, &rc, 1)) == 0)
  61. err_quit("child %d terminated unexpectedly", i);
  62. cptr[i].child_status = 0;
  63. navail++;
  64. if (--nsel == 0)
  65. break;  /* all done with select() results */
  66. }
  67. }
  68. }
  69. }
  70. /* end serv05a */
  71. void
  72. sig_int(int signo)
  73. {
  74. int     i;
  75. void    pr_cpu_time(void);
  76. /* 4terminate all children */
  77. for (i = 0; i < nchildren; i++)
  78. kill(cptr[i].child_pid, SIGTERM);
  79. while (wait(NULL) > 0)       /* wait for all children */
  80. ;
  81. if (errno != ECHILD)
  82. err_sys("wait error");
  83. pr_cpu_time();
  84. for (i = 0; i < nchildren; i++)
  85. printf("child %d, %ld connections\n", i, cptr[i].child_count);
  86. exit(0);
  87. }

编译命令:

gcc server.c child.c pr_cpu_time.c web_child.c -o server -lunp

版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。

时间: 2024-07-29 15:58:46

unix网络编程各种TCP客户-服务器程序设计实例(三)的相关文章

unix网络编程各种TCP客户-服务器程序设计实例附环境搭建和编译方法(一)

一,到http://download.csdn.net/detail/ts173383201/4505201去下载源代码,然后解压: 二,cd到你解压后的文件夹下,就是有configure的那个目录下,执行命令./configure: 三,执行cd lib跳到lib目录下,执行make命令,会在上层目录(就是刚才有configure那个目录)生成libunp.a文件 四,复制这个静态库libunp.a到/usr/lib/和/usr/lib64/中; 五,接下来在目录中找到unp.h和config

unix网络编程各种TCP客户-服务器程序设计实例(二)

本节我们接着介绍另外的几种TCP客户-服务器程序: 第四种:TCP并发服务器,每个客户一个子线程 在我们前面的并发服务器程序例子中可以看出:父进程接受连接,派生子进程,子进程处理与客户的交互. 这种模式的问题: fork()是昂贵的.内存映像要从父进程拷贝到子进程,所有描述字要在子进程中复制等等. fork()子进程后,需要用进程间通信在父子进程之间传递信息. 一个进程中的所有线程共享相同的全局内存,这使得线程很容易共享信息,但是这种简易型也带来了同步问题.一个进程中的所有线程不仅共享全局变量,

UNIX网络编程入门——TCP客户/服务器程序详解

前言 最近刚开始看APUE和UNP来学习socket套接字编程,因为网络这方面我还没接触过,要等到下学期才上计算机网络这门课,所以我就找了本教材啃了一两天,也算是入了个门. 至于APUE和UNP这两本书,书是好书,网上也说这书是给进入unix网络编程领域初学者的圣经,这个不可置否,但这个初学者,我认为指的是接受过完整计算机本科教育的研究生初学者,需要具有完整计算机系统,体系结构,网络基础知识.基础没打好就上来啃书反而会适得其反,不过对于我来说也没什么关系,因为基础课也都上得差不多了,而且如果书读

【UNIX网络编程】TCP客户/服务器程序示例

做一个简单的回射服务器: 客户从标准输入读入一行文本,写给服务器 -> 服务器从网络输入读入这行文本,并回射给客户 -> 客户从网络输入读入这行回射文本,并显示在标准输出上 以下是我的代码(部分.h文件是由unpv13e文件夹中的.c文件改名得到) #include "../unpv13e/unp.h" #include "../unpv13e/apueerror.h" #include "../unpv13e/wrapsock.h"

《UNIX网络编程》TCP客户端服务器:并发、消息回显

经过小小改动,把前面基础的例子做出一点修改. 并发服务器,服务器每accept一个请求就fork()一个新的子进程. 编译运行方法同前一篇. /*client_tcp.c*/ #include <stdio.h> #include <unistd.h> #include <stdlib.h> #include <sys/types.h> #include <sys/socket.h> #include <sys/un.h> #incl

Java网络编程(tcp在服务器上应用多线程)

package org.tcp; import java.io.BufferedReader; import java.io.InputStreamReader; import java.io.PrintStream; import java.net.Socket; public class EchoThread implements Runnable { private Socket client = null; public EchoThread(Socket client){ this.c

《UNIX网络编程》入门客户端服务器例子

最近在看<UNIX网络编程>(简称unp)和<Linux程序设计>,对于unp中第一个获取服务器时间的例子,实践起来总是有点头痛的,因为作者将声明全部包含在了unp.h里,导致后面编写代码会对这个头文件造成依赖,而学习不到调用了相应功能之后,应该包含哪些确切的头文件. 再者,我下载了unp.h之后,头文件包含再次产生了其他的依赖缺失,因此便参考了<Linux程序设计>中socket一章的入门例子的头文件包含,并且编译中仍然找不到的包含或者是宏定义在unp.h中搜索并粘贴

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

TCP客户与服务器进程之间发生的重大事件时间表 TCP服务器 socket() --- bind() --- listen() --- accept() --- read() --- write --- read() --- close TCP客户 socket() --- connect() --- write() --- read()  --- close() 套接字函数简介 int socket(int family, int type, int protocol); 指定要用的通信协议类

Unix网络编程-poll模型echo服务器

poll函数和select函数差不多.以下是一个简单的回显服务器 #include <iostream> using namespace std; #include <poll.h> #include <limits.h> #define OPEN_MAX 64 int main() { int i, maxi, listenfd, connfd, sockfd; int nready; ssize_t n; socklen_t clilen; struct pollf