当前位置:   article > 正文

浅谈并发服务器---多进程并发---3_多进程并发服务器

多进程并发服务器

            

                   当父进程产生新的子进程后,父,子进程共享父进程在调用fork之前的所有描述符,一般情况下,接下来父进程只负责

接收客户请求,而子进程只负责处理客户请求。关闭不需要的描述符既可以节省系统资源,又可以防止父,子进程同时对共享描

述符进程操作,产生不可预计的后果。

                  此外,由于当fork()函数返回后,与监听和已连接描述符相关联的文件表项的访问计数值均加一,当父进程调用close关

闭已连接描述符时,只是将访问计数值减1,而描述符只在访问计数为0时才真正关闭,所以为了正确地关闭链接,当调用fork()函数

后父进程将不需要的已连接描述符(accept函数返回的描述符)关闭,而子进程关闭不需要的监听描述符(socket函数返回的描述符)。

                                          

                             多进程并发服务器实例:    


    服务器端的程序步骤如下:

  1. /*
  2. * =====================================================================================
  3. *
  4. * Filename: server.c
  5. *
  6. * Description: 多进程并发服务器的server端程序
  7. *
  8. * Version: 1.0
  9. * Created: 2014年07月17日 09时45分30秒
  10. * Revision: none
  11. * Compiler: gcc
  12. * CopyRight: open , free , share
  13. * Author: yexingkong(zhangbaoqing)
  14. * Email: abqyexingkong@gmail.com
  15. * Company: Xi'an University of post and Telecommunications
  16. *
  17. * =====================================================================================
  18. */
  19. #include <unistd.h>
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23. #include <sys/types.h>
  24. #include <sys/socket.h>
  25. #include <netinet/in.h>
  26. #include <arpa/inet.h>
  27. #define SERV_PORT 4507 //服务端的端口
  28. #define LISTENQ 12 //链接请求队列的最大长度
  29. void my_err(const char *err_string, int err_line)
  30. {
  31. fprintf(stderr,"line: %d",err_line);
  32. perror(err_string);
  33. exit(1);
  34. }
  35. int main()
  36. {
  37. int sock_fd,conn_fd;
  38. int optval;
  39. int ret;
  40. int name_num;
  41. pid_t pid;
  42. socklen_t cli_len;
  43. struct sockaddr_in cli_addr,serv_addr;
  44. //创建一个TCPT套接字
  45. sock_fd = socket(AF_INET, SOCK_STREAM, 0);
  46. {
  47. if(sock_fd < 0)
  48. {
  49. my_err("socket", __LINE__);
  50. }
  51. }
  52. //设置该套接字使之可以重新绑定端口
  53. optval = 1;
  54. if(setsockopt(sock_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(int)) < 0)
  55. {
  56. my_err("setsockopt", __LINE__);
  57. }
  58. //初始化服务端地址结构
  59. memset(&serv_addr, 0 , sizeof(struct sockaddr_in));
  60. serv_addr.sin_family = AF_INET;
  61. serv_addr.sin_port = htons(SERV_PORT);
  62. serv_addr.sin_addr.s_addr = htons(INADDR_ANY);
  63. //将套接字绑定到本地端口
  64. if(bind(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr_in)) < 0)
  65. {
  66. my_err("bind", __LINE__);
  67. }
  68. //将套接字转化为监听套接字
  69. if(listen(sock_fd, LISTENQ))
  70. {
  71. my_err("listen", __LINE__);
  72. }
  73. cli_len = sizeof(struct sockaddr_in);
  74. while(1)
  75. {
  76. //通过accept接收客户端的链接请求,并返回链接套接字
  77. conn_fd = accept(sock_fd, (struct sockaddr *)&cli_addr, &cli_len);
  78. if(conn_fd < 0)
  79. {
  80. my_err("accept", __LINE__);
  81. }
  82. printf("accept a new client , ip: %s\n", inet_ntoa(cli_addr.sin_addr));
  83. //创建一个子进程处理刚刚接收的链接请求
  84. if((pid = fork()) == 0)
  85. {
  86. close(sock_fd); //子进程关闭监听描述符
  87. //child handle with something
  88. //...............
  89. exit(0); //结束子进程
  90. }else if(pid > 0) //父进程关闭刚刚接收的链接请求,执行accept等待其他链接请求
  91. {
  92. close(conn_fd); //父进程关闭已连接描述符
  93. continue;
  94. }
  95. else {
  96. printf("fork() error\n");
  97. exit(1);
  98. }
  99. }
  100. close(sock_fd);
  101. return 0;
  102. }

客户端程序如下 :

  1. /*
  2. * =====================================================================================
  3. *
  4. * Filename: client.c
  5. *
  6. * Description: 多进程并发服务器的client端程序
  7. *
  8. * Version: 1.0
  9. * Created: 2014年07月17日 10时18分16秒
  10. * Revision: none
  11. * Compiler: gcc
  12. * CopyRight: open , free , share
  13. * Author: yexingkong(zhangbaoqing)
  14. * Email: abqyexingkong@gmail.com
  15. * Company: Xi'an University of post and Telecommunications
  16. *
  17. * =====================================================================================
  18. */
  19. #include<stdio.h>
  20. #include<string.h>
  21. #include<stdlib.h>
  22. #include<unistd.h>
  23. #include<sys/types.h>
  24. #include<sys/socket.h>
  25. #include<string.h>
  26. #include<errno.h>
  27. #include<netinet/in.h>
  28. #include<arpa/inet.h>
  29. #include<netdb.h>
  30. #define SERV_PORT 4507 //服务器端的端口
  31. void my_err(const char * err_string, int err_line)
  32. {
  33. fprintf(stderr,"%d",err_line);
  34. perror(err_string);
  35. exit(1);
  36. }
  37. int main(int argc, char **argv)
  38. {
  39. int i;
  40. int ret;
  41. int sock_fd;
  42. struct sockaddr_in serv_addr;
  43. struct hostent *he;
  44. //检查参数的个数
  45. if (argc != 2)
  46. {
  47. printf("Usage: %s [serv_address]\n",argv[0]);
  48. exit(1);
  49. }
  50. if ((he=gethostbyname(argv[1])) == NULL)
  51. {
  52. printf("gethostbyname() error\n");
  53. exit(1);
  54. }
  55. //创建一个TCP套接字
  56. sock_fd = socket (AF_INET, SOCK_STREAM, 0);
  57. if (sock_fd < 0)
  58. {
  59. my_err("socket", __LINE__);
  60. }
  61. //初始化服务器端的端口与地址
  62. memset(&serv_addr, 0, sizeof (struct sockaddr_in));
  63. serv_addr.sin_family = AF_INET;
  64. serv_addr.sin_port = htons(SERV_PORT);
  65. serv_addr.sin_addr = *((struct in_addr *)he->h_addr);
  66. //向服务器端发送链接请求
  67. if (connect(sock_fd, (struct sockaddr *)&serv_addr, sizeof(struct sockaddr)) < 0)
  68. {
  69. my_err("connect", __LINE__);
  70. }
  71. //函数调用
  72. //................
  73. close(sock_fd);
  74. return 0;
  75. }


声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/IT小白/article/detail/197665
推荐阅读
相关标签
  

闽ICP备14008679号