进程通信(信号量、匿名管道、命名管道、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