加入收藏 | 设为首页 | 会员中心 | 我要投稿 辽源站长网 (https://www.0437zz.com/)- 云专线、云连接、智能数据、边缘计算、数据安全!
当前位置: 首页 > 运营中心 > 网站设计 > 教程 > 正文

TCP/IP网络编程之进程与间通信

发布时间:2019-11-09 13:54:45 所属栏目:教程 来源:Hu先生Linux后台开发
导读:进程间通信基本概念 进程间通信意味着两个不同进程间可以交换数据,为了完成这一点,操作系统中应提供两个进程可以同时访问的内存空间。但我们知道,进程具有完全独立的内存结构,就连通过fork函数创建的子进程也不会和父进程共享内存,因此,进程间通信只

编译pipe2.c并运行

  1. # gcc pipe2.c -o pipe2 
  2. # ./pipe2 
  3. Parent proc output: Who are you? 
  4. Child proc output: Thank you for your message 

运行结果和我们设想一致,不过如果尝试将18行的代码注释后再运行,虽然这行代码只将运行时间延迟了两秒,但一旦注释便会引发错误,是什么原因呢?

向管道传递数据时,先读的进程会把数据取走。简言之,数据进入管道后成为无主数据,也就是通过read函数先读取数据的进程将得到数据,即使该进程将数据传到了管道。因此,注释第18行将产生问题,在第19行,子进程将读回自己在第17行向管道发送的数据。结果父进程调用read函数后将无限期等待数据进入管道。

从上述示例可以看到,只用一个管道进行双向通信并非易事,为了简化在进行双向通信时,既然一个管道很难完成的任务,不如就让两个管道来一起完成?因此创建两个管道,各自负责不同的数据流动即可。其过程如图1-4所示

TCP/IP网络编程之进程与间通信

图1-4 双向通信模型2

由图1-4可知,使用两个管道可以解决单单通过一个管道来进行双向通信的麻烦,下面采用上述模型来改进pipe2.c。

pipe3.c

  1. #include <stdio.h> 
  2. #include <unistd.h> 
  3. #define BUF_SIZE 30 
  4. int main(int argc, char *argv[]) 
  5. int fds1[2], fds2[2]; 
  6. char str1[] = "Who are you?"; 
  7. char str2[] = "Thank you for your message"; 
  8. char buf[BUF_SIZE]; 
  9. pid_t pid; 
  10. pipe(fds1), pipe(fds2); 
  11. pid = fork(); 
  12. if (pid == 0) 
  13. write(fds1[1], str1, sizeof(str1)); 
  14. read(fds2[0], buf, BUF_SIZE); 
  15. printf("Child proc output: %s n", buf); 
  16. else 
  17. read(fds1[0], buf, BUF_SIZE); 
  18. printf("Parent proc output: %s n", buf); 
  19. write(fds2[1], str2, sizeof(str2)); 
  20. sleep(3); 
  21. return 0; 
  • 第13行:创建两个管道
  • 第17、33行:子进程可以通过数组fds1指向的管道向父进程传输数据
  • 第18、25行:父进程可以通过数组fds2指向的管道向子进程传输数据
  • 第26行:没有太大的意义,只是为了延迟父进程终止的插入的代码

编译pipe3.c并运行

  1. # gcc pipe3.c -o pipe3 
  2. # ./pipe3 
  3. Parent proc output: Who are you? 
  4. Child proc output: Thank you for your message 

运用进程间通信

上一节学习了基于管道的进程间通信方法,接下来将其运用到网络代码中。如前所述,进程间通信与创建服务端并没有直接关联,但有助于理解操作系统。

保存消息的回声服务端

扩展TCP/IP网络编程之多进程服务端(二)这一章的echo_mpserv.c,添加将回声客户端传输的字符串按序保存到文件中。我们可以将这个任务交给另外的进程,换言之,另行创建进程,从向客户端服务的进程字符串信息。当然,该过程需要创建用于接收数据的管道。

下面给出示例,该示例可以与任意回声客户端配合运行,我们将用之前介绍过的echo_mpserv.c。

echo_storeserv.c

  1. #include <stdio.h> 
  2. #include <stdlib.h> 
  3. #include <string.h> 
  4. #include <unistd.h> 
  5. #include <signal.h> 
  6. #include <sys/wait.h> 
  7. #include <arpa/inet.h> 
  8. #include <sys/socket.h> 
  9. #define BUF_SIZE 100 
  10. void error_handling(char *message); 
  11. void read_childproc(int sig); 
  12. int main(int argc, char *argv[]) 
  13. int serv_sock, clnt_sock; 
  14. struct sockaddr_in serv_adr, clnt_adr; 
  15. int fds[2]; 
  16. pid_t pid; 
  17. struct sigaction act; 
  18. socklen_t adr_sz; 
  19. int str_len, state; 
  20. char buf[BUF_SIZE]; 
  21. if (argc != 2) 
  22. printf("Usage : %s <port>n", argv[0]); 
  23. exit(1); 
  24. act.sa_handler = read_childproc; 
  25. sigemptyset(&act.sa_mask); 
  26. act.sa_flags = 0; 
  27. state = sigaction(SIGCHLD, &act, 0); 
  28. serv_sock = socket(PF_INET, SOCK_STREAM, 0); 
  29. memset(&serv_adr, 0, sizeof(serv_adr)); 
  30. serv_adr.sin_family = AF_INET; 
  31. serv_adr.sin_addr.s_addr = htonl(INADDR_ANY); 
  32. serv_adr.sin_port = htons(atoi(argv[1])); 
  33. if (bind(serv_sock, (struct sockaddr *)&serv_adr, sizeof(serv_adr)) == -1) 
  34. error_handling("bind() error"); 
  35. if (listen(serv_sock, 5) == -1) 
  36. error_handling("listen() error"); 
  37. pipe(fds); 
  38. pid = fork(); 
  39. if (pid == 0) 
  40. FILE *fp = fopen("echomsg.txt", "wt"); 
  41. char msgbuf[BUF_SIZE]; 
  42. int i, len; 
  43. for (i = 0; i < 10; i++) 
  44. len = read(fds[0], msgbuf, BUF_SIZE); 
  45. fwrite((void *)msgbuf, 1, len, fp); 
  46. fclose(fp); 
  47. return 0; 
  48. while (1) 
  49. adr_sz = sizeof(clnt_adr); 
  50. clnt_sock = accept(serv_sock, (struct sockaddr *)&clnt_adr, &adr_sz); 
  51. if (clnt_sock == -1) 
  52. continue; 
  53. else 
  54. puts("new client connected..."); 
  55. pid = fork(); 
  56. if (pid == 0) 
  57. close(serv_sock); 
  58. while ((str_len = read(clnt_sock, buf, BUF_SIZE)) != 0) 
  59. write(clnt_sock, buf, str_len); 
  60. write(fds[1], buf, str_len); 
  61. close(clnt_sock); 
  62. puts("client disconnected..."); 
  63. return 0; 
  64. else 
  65. close(clnt_sock); 
  66. close(serv_sock); 
  67. return 0; 
  68. void read_childproc(int sig) 
  69. pid_t pid; 
  70. int status; 
  71. pid = waitpid(-1, &status, WNOHANG); 
  72. printf("removed proc id: %d n", pid); 
  73. void error_handling(char *message) 
  74. fputs(message, stderr); 
  75. fputc('n', stderr); 
  76. exit(1); 
  77. }  
  • 第47、48行:第47行创建管道,第48行创建负责保存文件的进程
  • 第49~62行:第49行创建的子进程运行区域,该区域从管道出口fds[0]读取数据并保存到文件中。另外,上述服务端并不终止运行,而是不断向客户端提供服务。因此,数据在文件中累计到一定程序即关闭文件,该过程通过第55行的循环完成
  • 第80行:第73行通过fork函数创建的所有子进程将复制第47行创建的管道的文件描述符,因此,可以通过管道入口fds[1]传递字符串信息

(编辑:辽源站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

推荐文章
    热点阅读