进程通信(信号量、匿名管道、命名管道、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 }
结果:
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.命名管道
原理:
源码:
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 }
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网络进程通信
原理:
源码:
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 }
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 }