转自:操作系统-进程通信(信号量、匿名管道、命名管道、Socket) - yocichen - 博客园
具体的概念就没必要说了,参考以下链接。
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 }
结果:
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 }
(注意:该匿名管道程序为Linux系统开发,注意运行环境,windows下使用CodeBlocks可以运行)
3.命名管道
原理:
源码:
Server
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 }
Client
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 }
4.Socket网络进程通信
原理:
源码:
Server
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 }
Client
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 }