成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

TCP/IP網(wǎng)絡(luò)編程之進(jìn)程與進(jìn)程間通信

網(wǎng)絡(luò) 通信技術(shù)
進(jìn)程間通信意味著兩個(gè)不同進(jìn)程間可以交換數(shù)據(jù),為了完成這一點(diǎn),操作系統(tǒng)中應(yīng)提供兩個(gè)進(jìn)程可以同時(shí)訪問的內(nèi)存空間。但我們知道,進(jìn)程具有完全獨(dú)立的內(nèi)存結(jié)構(gòu),就連通過fork函數(shù)創(chuàng)建的子進(jìn)程也不會(huì)和父進(jìn)程共享內(nèi)存,因此,進(jìn)程間通信只能通過其他特殊方法完成。

 [[281737]]

進(jìn)程間通信基本概念

進(jìn)程間通信意味著兩個(gè)不同進(jìn)程間可以交換數(shù)據(jù),為了完成這一點(diǎn),操作系統(tǒng)中應(yīng)提供兩個(gè)進(jìn)程可以同時(shí)訪問的內(nèi)存空間。但我們知道,進(jìn)程具有完全獨(dú)立的內(nèi)存結(jié)構(gòu),就連通過fork函數(shù)創(chuàng)建的子進(jìn)程也不會(huì)和父進(jìn)程共享內(nèi)存,因此,進(jìn)程間通信只能通過其他特殊方法完成。

基于管道實(shí)現(xiàn)進(jìn)程間通信

圖1-1表示基于管道(PIPE)的進(jìn)程間通信結(jié)構(gòu)模型

 

TCP/IP網(wǎng)絡(luò)編程之進(jìn)程與間通信

 

圖1-1 基于管道的進(jìn)程間通信模型

從圖1-1可以看到,為了完成進(jìn)程間通信,需要?jiǎng)?chuàng)建管道。管道并非屬于進(jìn)程資源,而是和套接字一樣,屬于操作系統(tǒng)資源(也就不是fork函數(shù)的復(fù)制對(duì)象)。下面介紹創(chuàng)建管道函數(shù)

  1. #include 
  2. int pipe (int filedes[2]);//成功時(shí)返回0,失敗時(shí)返回-1 
  • filedes[0]:通過管道接收數(shù)據(jù)時(shí)使用的文件描述符,即管道出口
  • filedes[1]:通過管道傳輸數(shù)據(jù)時(shí)使用的文件描述符,即管道入口

以長度為2的int數(shù)組地址值作為參數(shù)調(diào)用上述函數(shù)時(shí),數(shù)組中存有兩個(gè)文件描述符,它們將被用作管道的出口和入口。父進(jìn)程調(diào)用該函數(shù)時(shí)將創(chuàng)建管道,同時(shí)獲取對(duì)應(yīng)于出入口的文件描述符,此時(shí)父進(jìn)程可以讀寫同一管道。但父進(jìn)程的目的是與子進(jìn)程進(jìn)行數(shù)據(jù)交換,因此需要將入口和出口中的一個(gè)文件描述符傳遞給子進(jìn)程,如何完成傳遞呢?答案還是調(diào)用fork函數(shù)。

  1. pipe1.c 
  2. #include <stdio.h> 
  3. #include <unistd.h> 
  4. #define BUF_SIZE 30 
  5. int main(int argc, char *argv[]) 
  6. int fds[2]; 
  7. char str[] = "Who are you?"
  8. char buf[BUF_SIZE]; 
  9. pid_t pid; 
  10. pipe(fds); 
  11. pid = fork(); 
  12. if (pid == 0) 
  13. write(fds[1], str, sizeof(str)); 
  14. else 
  15. read(fds[0], buf, BUF_SIZE); 
  16. puts(buf); 
  17. return 0; 
  • 第12行:調(diào)用pipe函數(shù)創(chuàng)建管道,fds數(shù)組中保存用于I/O的文件描述符
  • 第13行:接著調(diào)用fork函數(shù),子進(jìn)程將同時(shí)擁有通過12行函數(shù)調(diào)用獲取的兩個(gè)文件描述符。注意!復(fù)制的并非管道,而是用于管道I/O的文件描述符。至此,父子進(jìn)程同時(shí)擁有I/O文件描述符
  • 第16、20行:子進(jìn)程通過第16行代碼向管道傳遞字符串,父進(jìn)程通過第20行代碼從管道接收字符串

編譯pipe1.c并運(yùn)行

  1. # gcc pipe1.c -o pipe1 
  2. # ./pipe1 
  3. Who are you? 

上述示例中的通信方法及路徑如圖1-2所示,重點(diǎn)在于,父子進(jìn)程都可以訪問管道的I/O路徑,但子進(jìn)程僅用輸入路徑,父進(jìn)程僅用輸出路徑

 

TCP/IP網(wǎng)絡(luò)編程之進(jìn)程與間通信

 

圖1-2 示例pipe1.c的通信路徑

以上就是管道的基本原理及通信方法,應(yīng)用管道時(shí)還有一部分內(nèi)容需要注意,通過雙向通信示例進(jìn)一步說明

通過管道進(jìn)行進(jìn)程間雙向通信

下面創(chuàng)建兩個(gè)進(jìn)程通過一個(gè)管道進(jìn)行雙向數(shù)據(jù)交換的示例,其通信方式如圖1-3所示

 

TCP/IP網(wǎng)絡(luò)編程之進(jìn)程與間通信

 

圖1-3 雙向通信模型1

從圖1-3可以看出,通過一個(gè)管道可以進(jìn)行雙向通信,但采用這種模型需格外小心,先給出示例,稍后再討論。

pipe2.c

  1. #include <stdio.h> 
  2. #include <unistd.h> 
  3. #define BUF_SIZE 30 
  4. int main(int argc, char *argv[]) 
  5. int fds[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(fds); 
  11. pid = fork(); 
  12. if (pid == 0) 
  13. write(fds[1], str1, sizeof(str1)); 
  14. sleep(2); 
  15. read(fds[0], buf, BUF_SIZE); 
  16. printf("Child proc output: %s \n", buf); 
  17. else 
  18. read(fds[0], buf, BUF_SIZE); 
  19. printf("Parent proc output: %s \n", buf); 
  20. write(fds[1], str2, sizeof(str2)); 
  21. sleep(3); 
  22. return 0; 
  • 第17~20行:子進(jìn)程運(yùn)行區(qū)域,通過第17行行傳輸數(shù)據(jù),通過第19行接收數(shù)據(jù)。第18行的sleep函數(shù)至關(guān)重要,這一點(diǎn)稍后再討論
  • 第24~26行:父進(jìn)程的運(yùn)行區(qū)域,通過第24行接收數(shù)據(jù),這是為了接收第17行子進(jìn)程傳輸?shù)臄?shù)據(jù)。另外通過第26行傳輸數(shù)據(jù),這些數(shù)據(jù)將被第19行的子進(jìn)程接收
  • 第27行:父進(jìn)程先終止時(shí)會(huì)彈出命令提示符,這時(shí)子進(jìn)程仍然在工作,故不會(huì)產(chǎn)生問題。這條語句主要是為了防止子進(jìn)程終止前彈出命令提示符(故可刪除)

編譯pipe2.c并運(yùn)行

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

運(yùn)行結(jié)果和我們?cè)O(shè)想一致,不過如果嘗試將18行的代碼注釋后再運(yùn)行,雖然這行代碼只將運(yùn)行時(shí)間延遲了兩秒,但一旦注釋便會(huì)引發(fā)錯(cuò)誤,是什么原因呢?

向管道傳遞數(shù)據(jù)時(shí),先讀的進(jìn)程會(huì)把數(shù)據(jù)取走。簡(jiǎn)言之,數(shù)據(jù)進(jìn)入管道后成為無主數(shù)據(jù),也就是通過read函數(shù)先讀取數(shù)據(jù)的進(jìn)程將得到數(shù)據(jù),即使該進(jìn)程將數(shù)據(jù)傳到了管道。因此,注釋第18行將產(chǎn)生問題,在第19行,子進(jìn)程將讀回自己在第17行向管道發(fā)送的數(shù)據(jù)。結(jié)果父進(jìn)程調(diào)用read函數(shù)后將無限期等待數(shù)據(jù)進(jìn)入管道。

從上述示例可以看到,只用一個(gè)管道進(jìn)行雙向通信并非易事,為了簡(jiǎn)化在進(jìn)行雙向通信時(shí),既然一個(gè)管道很難完成的任務(wù),不如就讓兩個(gè)管道來一起完成?因此創(chuàng)建兩個(gè)管道,各自負(fù)責(zé)不同的數(shù)據(jù)流動(dòng)即可。其過程如圖1-4所示

 

TCP/IP網(wǎng)絡(luò)編程之進(jìn)程與間通信

 

圖1-4 雙向通信模型2

由圖1-4可知,使用兩個(gè)管道可以解決單單通過一個(gè)管道來進(jìn)行雙向通信的麻煩,下面采用上述模型來改進(jìn)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; 
  22. }   
  • 第13行:創(chuàng)建兩個(gè)管道
  • 第17、33行:子進(jìn)程可以通過數(shù)組fds1指向的管道向父進(jìn)程傳輸數(shù)據(jù)
  • 第18、25行:父進(jìn)程可以通過數(shù)組fds2指向的管道向子進(jìn)程傳輸數(shù)據(jù)
  • 第26行:沒有太大的意義,只是為了延遲父進(jìn)程終止的插入的代碼

編譯pipe3.c并運(yùn)行

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

運(yùn)用進(jìn)程間通信

上一節(jié)學(xué)習(xí)了基于管道的進(jìn)程間通信方法,接下來將其運(yùn)用到網(wǎng)絡(luò)代碼中。如前所述,進(jìn)程間通信與創(chuàng)建服務(wù)端并沒有直接關(guān)聯(lián),但有助于理解操作系統(tǒng)。

保存消息的回聲服務(wù)端

擴(kuò)展TCP/IP網(wǎng)絡(luò)編程之多進(jìn)程服務(wù)端(二)這一章的echo_mpserv.c,添加將回聲客戶端傳輸?shù)淖址葱虮4娴轿募小N覀兛梢詫⑦@個(gè)任務(wù)交給另外的進(jìn)程,換言之,另行創(chuàng)建進(jìn)程,從向客戶端服務(wù)的進(jìn)程字符串信息。當(dāng)然,該過程需要?jiǎng)?chuàng)建用于接收數(shù)據(jù)的管道。

下面給出示例,該示例可以與任意回聲客戶端配合運(yùn)行,我們將用之前介紹過的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行創(chuàng)建管道,第48行創(chuàng)建負(fù)責(zé)保存文件的進(jìn)程
  • 第49~62行:第49行創(chuàng)建的子進(jìn)程運(yùn)行區(qū)域,該區(qū)域從管道出口fds[0]讀取數(shù)據(jù)并保存到文件中。另外,上述服務(wù)端并不終止運(yùn)行,而是不斷向客戶端提供服務(wù)。因此,數(shù)據(jù)在文件中累計(jì)到一定程序即關(guān)閉文件,該過程通過第55行的循環(huán)完成
  • 第80行:第73行通過fork函數(shù)創(chuàng)建的所有子進(jìn)程將復(fù)制第47行創(chuàng)建的管道的文件描述符,因此,可以通過管道入口fds[1]傳遞字符串信息

編譯echo_storeserv.c并運(yùn)行

  1. # gcc echo_storeserv.c -o echo_storeserv 
  2. # ./echo_storeserv 8500 
  3. new client connected... 
  4. new client connected... 
  5. client disconnected... 
  6. removed proc id: 8647 
  7. removed proc id: 8633 
  8. client disconnected... 
  9. removed proc id: 8644 

運(yùn)行結(jié)果echo_mpclient ONE:

  1. # ./echo_mpclient 127.0.0.1 8500 
  2. Hello world! 
  3. Message from server: Hello world! 
  4. Hello Amy! 
  5. Message from server: Hello Amy! 
  6. Hello Tom! 
  7. Message from server: Hello Tom! 
  8. Hello Jack! 
  9. Message from server: Hello Jack! 
  10. Hello Rose! 
  11. Message from server: Hello Rose! 
  12. q   

運(yùn)行結(jié)果echo_mpclient TWO:

  1. # ./echo_mpclient 127.0.0.1 8500 
  2. Hello Java! 
  3. Message from server: Hello Java! 
  4. Hello Python! 
  5. Message from server: Hello Python! 
  6. Hello Golang! 
  7. Message from server: Hello Golang! 
  8. Hello Spring! 
  9. Message from server: Hello Spring! 
  10. Hello Flask! 
  11. Message from server: Hello Flask! 

打印echomsg.txt文件

  1. # cat echomsg.txt 
  2. Hello world! 
  3. Hello Amy! 
  4. Hello Java! 
  5. Hello Python! 
  6. Hello Tom! 
  7. Hello Jack! 
  8. Hello Rose! 
  9. Hello Golang! 
  10. Hello Spring! 
  11. Hello Flask! 

如上運(yùn)行結(jié)果所示,啟動(dòng)多個(gè)客戶端向服務(wù)端傳輸數(shù)據(jù)時(shí),文件中累計(jì)一定數(shù)量的字符串后(共調(diào)用十次fwrite函數(shù)),可以打開echomsg.txt存入字符串。

 

責(zé)任編輯:武曉燕 來源: 今日頭條
相關(guān)推薦

2017-08-06 00:05:18

進(jìn)程通信開發(fā)

2015-04-24 09:48:59

TCPsocketsocket編程

2021-01-22 10:58:16

網(wǎng)絡(luò)安全進(jìn)程間碼如

2010-01-05 10:00:48

Linux進(jìn)程間通信

2020-11-04 07:17:42

Nodejs通信進(jìn)程

2011-06-22 17:09:50

QT 進(jìn)程 通信

2020-11-18 09:06:04

Python

2018-01-12 14:35:00

Linux進(jìn)程共享內(nèi)存

2017-06-19 13:36:12

Linux進(jìn)程消息隊(duì)列

2013-03-28 13:14:45

AIDL進(jìn)程間通信Android使用AI

2011-08-08 10:02:55

iPhone開發(fā) 進(jìn)程 通信

2021-02-14 21:05:05

通信消息系統(tǒng)

2024-01-05 08:41:31

進(jìn)程間通信IPC異步通信

2020-09-22 07:35:06

Linux線程進(jìn)程

2018-05-30 13:58:02

Linux進(jìn)程通信

2011-06-24 14:01:34

Qt QCOP 協(xié)議

2019-05-08 11:10:05

Linux進(jìn)程語言

2017-01-10 13:39:57

Python線程池進(jìn)程池

2020-04-29 15:10:16

Linux命令進(jìn)程

2019-09-18 20:07:06

AndroidTCP協(xié)議
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)

主站蜘蛛池模板: 日韩欧美二区 | 久久国产精品视频 | 欧美一级在线免费观看 | 天天躁日日躁狠狠躁2018小说 | 久久久久成人精品免费播放动漫 | 国内精品视频在线 | 国产精品视频一区二区三区 | 黄色在线免费观看视频网站 | 成人av电影免费在线观看 | 国产精品久久7777777 | 亚洲精品电影网在线观看 | 国产精品毛片一区二区三区 | 欧美一区二区在线观看视频 | 午夜电影合集 | 一区二区三区免费 | julia中文字幕久久一区二区 | 精品综合 | 亚洲成人中文字幕 | 人人人人人爽 | 久久久久久久久久一区 | 日韩精品中文字幕一区二区三区 | 国产一区高清 | 久久新 | 激情欧美一区二区三区中文字幕 | 欧美激情久久久久久 | 国产黄色在线观看 | 精品国产91乱码一区二区三区 | 看片91| 日韩欧美中文在线 | 久久精品国产99国产精品 | 精品视频www | 色黄网站 | 日日操夜夜干 | 欧美国产日韩精品 | 国产激情91久久精品导航 | 色花av| 亚洲精品一区二区三区四区高清 | 国产精品综合色区在线观看 | 日韩精品二区 | 日韩精品久久久久久 | av在线播放国产 |