1. 程式人生 > >作業系統-程序通訊(訊號量、匿名管道、命名管道、Socket)

作業系統-程序通訊(訊號量、匿名管道、命名管道、Socket)

程序通訊(訊號量、匿名管道、命名管道、Socket)

具體的概念就沒必要說了,參考以下連結。

Source Code:

1. 訊號量(生產者消費者問題)

 1 #include <iostream>
 2 #include <Windows.h>
 3 #include <process.h>
 4 #include <vector>
 5 using namespace std;
 6 
 7 #define STD _stdcall  //被呼叫者負責清棧
8 int BufferSize; //緩衝區大小 9 10 CRITICAL_SECTION CR; //臨界區 11 HANDLE Empty = NULL; //訊號量:空閒緩衝區 12 HANDLE Full = NULL; //訊號量:滿緩衝區 13 vector<int>Buffer; //緩衝區 14 15 /*生產者執行緒*/ 16 DWORD STD Producer(void *lp) 17 { 18 while(true)//自旋測試 19 { 20 //等待空緩衝區:P(empty) 21 WaitForSingleObject(Full, INFINITE);//
一直等待 22 //進入緩衝區P(mutex) 23 EnterCriticalSection(&CR); 24 //生產資料 25 int s = rand()%10; 26 Buffer.push_back(s); 27 cout << "Producer produces an element : " << s <<endl; 28 //退出緩衝區V(mutex) 29 LeaveCriticalSection(&CR);
30 //增加滿緩衝區V(full) 31 ReleaseSemaphore(Empty, 1, NULL); 32 //睡一會兒 33 Sleep(2000); 34 } 35 } 36 37 /*消費者執行緒*/ 38 DWORD STD Consumer(void *lp) 39 { 40 while(true)//自旋測試 41 { 42 //等待滿緩衝區:P(empty) 43 WaitForSingleObject(Empty, INFINITE);//一直等待 44 //進入緩衝區P(mutex) 45 EnterCriticalSection(&CR); 46 //取出資料 47 int r = Buffer[Buffer.size()-1]; 48 Buffer.pop_back(); 49 cout << " Consumer consumes an element : " << r <<endl; 50 //退出緩衝區V(mutex) 51 LeaveCriticalSection(&CR); 52 //增加空緩衝區V(full) 53 ReleaseSemaphore(Full, 1, NULL); 54 //睡一會兒 55 Sleep(2000); 56 } 57 } 58 59 int main() 60 { 61 cout << "Input the number of BufferSize : "; cin >> BufferSize; 62 //建立訊號量 63 Empty = CreateSemaphore(NULL, 0, BufferSize, NULL); 64 Full = CreateSemaphore(NULL, BufferSize, BufferSize,NULL); 65 66 //初始化臨界區 67 InitializeCriticalSection(&CR); 68 69 int pNum, cNum; 70 cout << "Input the number of Producer(Max:10) : "; cin >> pNum; 71 cout << "Input the number of Consumer(Max:10) : "; cin >> cNum; 72 73 //建立執行緒 74 int i; 75 HANDLE handle[20]; 76 for(i=0; i<pNum; i++) 77 { 78 handle[i] = CreateThread(0, 0, &Producer, 0, 0, 0); 79 } 80 for(i=pNum; i<pNum+cNum; i++) 81 { 82 handle[i] = CreateThread(0, 0, &Consumer, 0, 0, 0); 83 } 84 85 //回收執行緒 86 WaitForMultipleObjects(pNum+cNum, handle, true, INFINITE); 87 88 //釋放執行緒 89 for(i=0; i<pNum+cNum; i++) 90 { 91 CloseHandle(handle[0]); 92 } 93 94 //釋放緩衝區 95 DeleteCriticalSection(&CR); 96 return 0; 97 }
View Code

結果:

2. 匿名管道(本地父程序與子程序通訊)

原理:

原始碼:

 1 /*
 2 *匿名管道:父子程序通訊
 3 *date : 2018/12/3
 4 *author : yocichen
 5 *status : Done
 6 */
 7 #include <unistd.h>
 8 #include <stdio.h>
 9 #include <stdlib.h>
10 #include <string.h>
11 
12 int main()
13 {
14     //pipe1 p to s, pipe2 s to p
15     int fd_1[2], fd_2[2];
16 
17     if(pipe(fd_1)<0 || pipe(fd_2)<0)//fail to create pipe
18     {
19         printf("Fail to create the pipe.\n");
20         return -1;
21     }
22 
23     char buf[256];//
24     const char *temp;
25 
26     //child
27     int fork_result = fork();
28     if(fork_result == 0)
29     {
30         close(fd_1[1]);//close read port
31         close(fd_2[0]);//close write port
32 
33         //read message
34         read(fd_1[0], buf, sizeof(buf));//read message from father port
35         printf("\nChild  : receive a message from pipe1: %s\n", buf);
36 
37         //write message
38         temp = "Hi, my parent, I love you too.";
39         write(fd_2[1], temp, strlen(temp));//child write message to pipe2
40     }
41 
42     else
43     {
44         close(fd_2[1]);
45         close(fd_1[0]);
46 
47         //write message
48         temp = "My child, I love you.";
49         write(fd_1[1], temp, strlen(temp));//parent write message to pipe1
50 
51         //read message
52         read(fd_2[0], buf, sizeof(buf));//read message from pipe2
53         printf("\nParent : receive a message from pipe2: %s\n", buf);
54     }
55     return 0;
56 }
View Code

(注意:該匿名管道程式為Linux系統開發,注意執行環境,windows下使用CodeBlocks可以執行)

3.命名管道

原理:

原始碼:

 1 #include <windows.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 int main()
 6 {
 7     //建立命名管道
 8     HANDLE namedPipe = CreateNamedPipeA("\\\\.\\pipe\\testName", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, 1, 1024, 1024, 0, NULL);
 9 
10     //校驗狀態
11     if(namedPipe == INVALID_HANDLE_VALUE)
12     {
13         printf("Server: Fail to create named pipe.\n");
14     }
15     else
16     {
17         printf("Server: Succeed to create pipe.\n");
18     }
19 
20     OVERLAPPED op;
21     ZeroMemory(&op, sizeof(OVERLAPPED));
22 
23     //建立事件物件
24     op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
25 
26     //等待連線
27     bool b = ConnectNamedPipe(namedPipe, &op);
28     printf("Server: Listen...\n");
29 
30     int status = WaitForSingleObject(op.hEvent, INFINITE);
31     //連線成功
32     if(status == 0)
33     {
34         printf("Server: Succeed to connect.\n");
35     }
36     else
37     {
38         printf("Server: Fail to connect.\n");
39     }
40 
41     //通訊
42     char buf[100] = "來玩個猜數遊戲吧!\n";
43     DWORD wp;
44     WriteFile(namedPipe, buf, strlen(buf), &wp, NULL);
45 
46     int ans = rand()%9+1;
47     while(status == 0)
48     {
49         ZeroMemory(buf, 100);
50         ReadFile(namedPipe, buf, 100, &wp, NULL);
51         printf("收到:%s\n", buf);
52 
53         if(int(buf[0] - '0') < ans)
54         {
55             WriteFile(namedPipe, "小了,再猜一次!\n", strlen("小了,再猜一次!\n"), &wp, NULL);
56         }
57         else if((buf[0]-'0') > ans)
58         {
59             WriteFile(namedPipe, "大了,再猜一次!\n", strlen("大了,再猜一次!\n"), &wp, NULL);
60         }
61         else
62         {
63             WriteFile(namedPipe, "猜對了!\n", strlen("小了,再猜一次!\n"), &wp, NULL);
64             break;
65         }
66 
67         if(buf[0] == '0')
68         {
69             printf("客戶已退出!\n");
70             break;
71         }
72     }
73 
74     //通訊結束
75     DisconnectNamedPipe(namedPipe);
76     return 0;
77 }
Server
 1 #include <windows.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 
 5 int main()
 6 {
 7     //檢查管道是否存在
 8     bool b = WaitNamedPipeA("\\\\.\\pipe\\testName", 0);
 9 
10     //開啟管道
11     HANDLE hFile = CreateFileA("\\\\.\\pipe\\testName", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
12 
13     //是否連線成功
14     if(b ==0 || hFile == INVALID_HANDLE_VALUE)
15     {
16         printf("Client: fail to connect.\n");
17         return 0;
18     }
19     else
20     {
21         printf("Client: Succeed to connect.\n");
22     }
23 
24     //通訊
25     char buf[100];
26     ZeroMemory(buf, 100);
27     DWORD rp;
28     ReadFile(hFile, buf, 100, &rp, NULL);//讀取
29     printf(buf);
30 
31     while(true)
32     {
33         printf("輸入數字:");
34         scanf("%s", buf);
35         WriteFile(hFile, buf, strlen(buf), &rp, NULL);
36 
37         while(ReadFile(hFile, buf, 100, &rp, NULL) == true)
38         {
39             printf("Server: ");
40             printf(buf);
41             break;
42         }
43     }
44 
45     CloseHandle(hFile);
46     return 0;
47 }
Client

4.Socket網路程序通訊

原理:

原始碼:

 1 /*注意標頭檔案順序*/
 2 #include <winsock2.h>
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 #pragma comment(lib, "ws2_32.lib")      //引入動態連結庫
 6 
 7 int main()
 8 {
 9     WORD ws_version = MAKEWORD(2, 2);   //指定Winsock version
10     WSADATA wsaData;                    //WSA 函式的引數
11 
12     /*初始化winsock*/
13     WSAStartup(ws_version, &wsaData);
14 
15     /*socket*/
16     SOCKET s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
17 
18     SOCKADDR_IN addr_server;
19     addr_server.sin_family = AF_INET;   //協議
20     addr_server.sin_port = htons(5050); //
21     addr_server.sin_addr.s_addr = htonl(INADDR_ANY);    //IP:任意IP
22 
23     /*bind*/
24     int bind_status;
25     bind_status = bind(s_server, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
26     if(bind_status == SOCKET_ERROR)
27     {
28         printf("bind error : fail to bind! \n"); 
29     }
30     else
31     {
32         printf("bind successfully!\n");
33     }
34 
35     /*listen*/
36     listen(s_server, 5);//max=5
37     printf("listening ... \n");
38 
39     SOCKADDR_IN addr_client;            //儲存client地址資訊
40     int len = sizeof(SOCKADDR);
41     int count = 0;                        //統計客戶數目
42     SOCKET s_client;                    //連線的socket
43 
44     char buf[1000];
45     while(true)
46     {
47         printf("等待客戶端連線...\n");
48         /*accept*/
49         s_client = accept(s_server, (SOCKADDR*)&addr_client, &len);
50         if(s_client == INVALID_SOCKET)
51         {
52             printf("Accept error : fail to accept client! ");
53         }
54         else//連線成功
55         {
56             count++;
57             printf("\nAccept successfully!\n");
58             
59             printf("---------------------------------------------\n");
60             printf(" 編號:%d \n", count);
61             printf(" Port:%d\n", ntohs(addr_client.sin_port));
62             printf(" IP:%s\n", inet_ntoa(addr_client.sin_addr));//inet_ntoa(SOCKADDR.in_addr)網路地址轉換為IP
63             
64             int recv_status = recv(s_client, buf, 100, 0);
65             if(recv_status > 0)
66             {
67                 printf("收到:");
68                 buf[recv_status] = 0x00;//截斷
69                 printf(buf);
70                 printf("\n---------------------------------------------\n");
71             }
72             const char *sendData = "你好!客戶端!我是伺服器";
73             send(s_client, sendData, strlen(sendData), 0);
74             closesocket(s_client);
75         }
76     }
77 
78     closesocket(s_server);      //關閉socket
79     WSACleanup();
80 
81     return 0;
82 }
Server
 1 #include <winsock2.h>
 2 #include <stdio.h>
 3 #include <stdlib.h>
 4 #include <windows.h>
 5 #include <iostream>
 6 #pragma comment(lib, "ws2_32.lib")      //引入動態連結庫
 7 #define SERVER_IP "192.168.31.102"        //客戶端IP
 8 using namespace std;
 9 
10 int main()
11 {
12     WORD ws_version = MAKEWORD(2, 2);   //指定Winsock version
13     WSADATA wsaData;                    //WSA 函式的引數
14 
15     /*初始化winsock*/
16     WSAStartup(ws_version, &wsaData);
17 
18     while(true)
19     {
20         /*socket*/
21         SOCKET s_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
22 
23         SOCKADDR_IN addr_server;
24         addr_server.sin_family = AF_INET;   //協議
25         addr_server.sin_port = htons(5050); //
26         addr_server.sin_addr.s_addr = inet_addr(SERVER_IP);
27 
28         char buf[100];
29         int send_status, recv_status;
30 
31         /*Connect*/
32         int cnct_status = connect(s_client, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
33         if(cnct_status == 0)//連線成功
34         {
35                 printf("\nConnecting... done\n");
36 
37                 //向服務端傳送訊息
38                 printf("輸入傳送資訊:");
39                 scanf("%s", buf);
40                 send_status = send(s_client, buf, 10, 0);
41                 if(send_status == SOCKET_ERROR)//傳送失敗
42                 {
43                     printf("send error!\n");
44                 }
45                 else
46                 {
47                     printf("傳送:%s\n", buf);
48                     //接受服務端訊息
49                     recv_status = recv(s_client, buf, 100, 0);
50                     buf[recv_status] = 0x00;//截斷
51                     printf("收到:%s\n", buf);
52                 }
53         }
54         else
55         {
56             printf("Test:fail to connect server! \n");
57         }
58         closesocket(s_client);
59     }
60 
61     WSACleanup();
62 
63     return 0;
64 }
Client