进程通信(信号量、匿名管道、命名管道、Socket)

具体的概念就没必要说了,参考以下链接。

Source Code:

1. 信号量(生产者消费者问题)

 #include <iostream>
#include <Windows.h>
#include <process.h>
#include <vector>
using namespace std; #define STD _stdcall //被调用者负责清栈
int BufferSize; //缓冲区大小 CRITICAL_SECTION CR; //临界区
HANDLE Empty = NULL; //信号量:空闲缓冲区
HANDLE Full = NULL; //信号量:满缓冲区
vector<int>Buffer; //缓冲区 /*生产者线程*/
DWORD STD Producer(void *lp)
{
while(true)//自旋测试
{
//等待空缓冲区:P(empty)
WaitForSingleObject(Full, INFINITE);//一直等待
//进入缓冲区P(mutex)
EnterCriticalSection(&CR);
//生产数据
int s = rand()%;
Buffer.push_back(s);
cout << "Producer produces an element : " << s <<endl;
//退出缓冲区V(mutex)
LeaveCriticalSection(&CR);
//增加满缓冲区V(full)
ReleaseSemaphore(Empty, , NULL);
//睡一会儿
Sleep();
}
} /*消费者线程*/
DWORD STD Consumer(void *lp)
{
while(true)//自旋测试
{
//等待满缓冲区:P(empty)
WaitForSingleObject(Empty, INFINITE);//一直等待
//进入缓冲区P(mutex)
EnterCriticalSection(&CR);
//取出数据
int r = Buffer[Buffer.size()-];
Buffer.pop_back();
cout << " Consumer consumes an element : " << r <<endl;
//退出缓冲区V(mutex)
LeaveCriticalSection(&CR);
//增加空缓冲区V(full)
ReleaseSemaphore(Full, , NULL);
//睡一会儿
Sleep();
}
} int main()
{
cout << "Input the number of BufferSize : "; cin >> BufferSize;
//创建信号量
Empty = CreateSemaphore(NULL, , BufferSize, NULL);
Full = CreateSemaphore(NULL, BufferSize, BufferSize,NULL); //初始化临界区
InitializeCriticalSection(&CR); int pNum, cNum;
cout << "Input the number of Producer(Max:10) : "; cin >> pNum;
cout << "Input the number of Consumer(Max:10) : "; cin >> cNum; //创建线程
int i;
HANDLE handle[];
for(i=; i<pNum; i++)
{
handle[i] = CreateThread(, , &Producer, , , );
}
for(i=pNum; i<pNum+cNum; i++)
{
handle[i] = CreateThread(, , &Consumer, , , );
} //回收线程
WaitForMultipleObjects(pNum+cNum, handle, true, INFINITE); //释放线程
for(i=; i<pNum+cNum; i++)
{
CloseHandle(handle[]);
} //释放缓冲区
DeleteCriticalSection(&CR);
return ;
}

结果:

2. 匿名管道(本地父进程与子进程通信)

原理:

源码:

 /*
*匿名管道:父子进程通信
*date : 2018/12/3
*author : yocichen
*status : Done
*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h> int main()
{
//pipe1 p to s, pipe2 s to p
int fd_1[], fd_2[]; if(pipe(fd_1)< || pipe(fd_2)<)//fail to create pipe
{
printf("Fail to create the pipe.\n");
return -;
} char buf[];//
const char *temp; //child
int fork_result = fork();
if(fork_result == )
{
close(fd_1[]);//close read port
close(fd_2[]);//close write port //read message
read(fd_1[], buf, sizeof(buf));//read message from father port
printf("\nChild : receive a message from pipe1: %s\n", buf); //write message
temp = "Hi, my parent, I love you too.";
write(fd_2[], temp, strlen(temp));//child write message to pipe2
} else
{
close(fd_2[]);
close(fd_1[]); //write message
temp = "My child, I love you.";
write(fd_1[], temp, strlen(temp));//parent write message to pipe1 //read message
read(fd_2[], buf, sizeof(buf));//read message from pipe2
printf("\nParent : receive a message from pipe2: %s\n", buf);
}
return ;
}

(注意:该匿名管道程序为Linux系统开发,注意运行环境,windows下使用CodeBlocks可以运行)

3.命名管道

原理:

源码:

 #include <windows.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
//创建命名管道
HANDLE namedPipe = CreateNamedPipeA("\\\\.\\pipe\\testName", PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_TYPE_BYTE, , , , , NULL); //校验状态
if(namedPipe == INVALID_HANDLE_VALUE)
{
printf("Server: Fail to create named pipe.\n");
}
else
{
printf("Server: Succeed to create pipe.\n");
} OVERLAPPED op;
ZeroMemory(&op, sizeof(OVERLAPPED)); //创建事件对象
op.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL); //等待连接
bool b = ConnectNamedPipe(namedPipe, &op);
printf("Server: Listen...\n"); int status = WaitForSingleObject(op.hEvent, INFINITE);
//连接成功
if(status == )
{
printf("Server: Succeed to connect.\n");
}
else
{
printf("Server: Fail to connect.\n");
} //通信
char buf[] = "来玩个猜数游戏吧!\n";
DWORD wp;
WriteFile(namedPipe, buf, strlen(buf), &wp, NULL); int ans = rand()%+;
while(status == )
{
ZeroMemory(buf, );
ReadFile(namedPipe, buf, , &wp, NULL);
printf("收到:%s\n", buf); if(int(buf[] - '') < ans)
{
WriteFile(namedPipe, "小了,再猜一次!\n", strlen("小了,再猜一次!\n"), &wp, NULL);
}
else if((buf[]-'') > ans)
{
WriteFile(namedPipe, "大了,再猜一次!\n", strlen("大了,再猜一次!\n"), &wp, NULL);
}
else
{
WriteFile(namedPipe, "猜对了!\n", strlen("小了,再猜一次!\n"), &wp, NULL);
break;
} if(buf[] == '')
{
printf("客户已退出!\n");
break;
}
} //通信结束
DisconnectNamedPipe(namedPipe);
return ;
}

Server

 #include <windows.h>
#include <stdio.h>
#include <stdlib.h> int main()
{
//检查管道是否存在
bool b = WaitNamedPipeA("\\\\.\\pipe\\testName", ); //打开管道
HANDLE hFile = CreateFileA("\\\\.\\pipe\\testName", GENERIC_READ | GENERIC_WRITE, , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); //是否连接成功
if(b == || hFile == INVALID_HANDLE_VALUE)
{
printf("Client: fail to connect.\n");
return ;
}
else
{
printf("Client: Succeed to connect.\n");
} //通信
char buf[];
ZeroMemory(buf, );
DWORD rp;
ReadFile(hFile, buf, , &rp, NULL);//读取
printf(buf); while(true)
{
printf("输入数字:");
scanf("%s", buf);
WriteFile(hFile, buf, strlen(buf), &rp, NULL); while(ReadFile(hFile, buf, , &rp, NULL) == true)
{
printf("Server: ");
printf(buf);
break;
}
} CloseHandle(hFile);
return ;
}

Client

4.Socket网络进程通信

原理:

源码:

 /*注意头文件顺序*/
#include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#pragma comment(lib, "ws2_32.lib") //引入动态链接库 int main()
{
WORD ws_version = MAKEWORD(, ); //指定Winsock version
WSADATA wsaData; //WSA 函数的参数 /*初始化winsock*/
WSAStartup(ws_version, &wsaData); /*socket*/
SOCKET s_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN addr_server;
addr_server.sin_family = AF_INET; //协议
addr_server.sin_port = htons(); //端口
addr_server.sin_addr.s_addr = htonl(INADDR_ANY); //IP:任意IP /*bind*/
int bind_status;
bind_status = bind(s_server, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
if(bind_status == SOCKET_ERROR)
{
printf("bind error : fail to bind! \n");
}
else
{
printf("bind successfully!\n");
} /*listen*/
listen(s_server, );//max=5
printf("listening ... \n"); SOCKADDR_IN addr_client; //存储client地址信息
int len = sizeof(SOCKADDR);
int count = ; //统计客户数目
SOCKET s_client; //连接的socket char buf[];
while(true)
{
printf("等待客户端连接...\n");
/*accept*/
s_client = accept(s_server, (SOCKADDR*)&addr_client, &len);
if(s_client == INVALID_SOCKET)
{
printf("Accept error : fail to accept client! ");
}
else//连接成功
{
count++;
printf("\nAccept successfully!\n"); printf("---------------------------------------------\n");
printf(" 编号:%d \n", count);
printf(" Port:%d\n", ntohs(addr_client.sin_port));
printf(" IP:%s\n", inet_ntoa(addr_client.sin_addr));//inet_ntoa(SOCKADDR.in_addr)网络地址转换为IP int recv_status = recv(s_client, buf, , );
if(recv_status > )
{
printf("收到:");
buf[recv_status] = 0x00;//截断
printf(buf);
printf("\n---------------------------------------------\n");
}
const char *sendData = "你好!客户端!我是服务器";
send(s_client, sendData, strlen(sendData), );
closesocket(s_client);
}
} closesocket(s_server); //关闭socket
WSACleanup(); return ;
}

Server

 #include <winsock2.h>
#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib, "ws2_32.lib") //引入动态链接库
#define SERVER_IP "192.168.31.102" //客户端IP
using namespace std; int main()
{
WORD ws_version = MAKEWORD(, ); //指定Winsock version
WSADATA wsaData; //WSA 函数的参数 /*初始化winsock*/
WSAStartup(ws_version, &wsaData); while(true)
{
/*socket*/
SOCKET s_client = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); SOCKADDR_IN addr_server;
addr_server.sin_family = AF_INET; //协议
addr_server.sin_port = htons(); //端口
addr_server.sin_addr.s_addr = inet_addr(SERVER_IP); char buf[];
int send_status, recv_status; /*Connect*/
int cnct_status = connect(s_client, (SOCKADDR*)&addr_server, sizeof(SOCKADDR));
if(cnct_status == )//连接成功
{
printf("\nConnecting... done\n"); //向服务端发送消息
printf("输入发送信息:");
scanf("%s", buf);
send_status = send(s_client, buf, , );
if(send_status == SOCKET_ERROR)//发送失败
{
printf("send error!\n");
}
else
{
printf("发送:%s\n", buf);
//接受服务端消息
recv_status = recv(s_client, buf, , );
buf[recv_status] = 0x00;//截断
printf("收到:%s\n", buf);
}
}
else
{
printf("Test:fail to connect server! \n");
}
closesocket(s_client);
} WSACleanup(); return ;
}

Client

操作系统-进程通信(信号量、匿名管道、命名管道、Socket)的更多相关文章

  1. 邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自http://www.cnblogs.com/kzloser/archive/2012/11/04/2753367.html#

    邮槽 通信流程: 服务器 客户端 注意: 邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输 邮槽可以实现一对多的单向通信,我们可以利用这个特点编写一个网络会议通知系统,而且实现这一的系 ...

  2. Linux进程通信之匿名管道

    进程间的通信方式 进程间的通信方式包括,管道.共享内存.信号.信号量.消息队列.套接字. 进程间通信的目的 进程间通信的主要目的是:数据传输.数据共享.事件通知.资源共享.进程控制等. 进程间通信之管 ...

  3. C#命名管道通信

    C#命名管道通信 最近项目中要用c#进程间通信,以前常见的方法包括RMI.发消息等.但在Windows下面发消息需要有窗口,我们的程序是一个后台运行程序,发消息不试用.RMI又用的太多了,准备用管道通 ...

  4. c# c++通信--命名管道通信

    进程间通信有很多种,windows上面比较简单的有管道通信(匿名管道及命名管道) 最近做个本机c#界面与c++服务进行通信的一个需求.简单用命名管道通信.msdn都直接有demo,详见下方参考. c+ ...

  5. [转]WINDOW进程通信的几种方式

    windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...

  6. 【windows 操作系统】进程间通信(IPC)简述|无名管道和命名管道 消息队列、信号量、共享存储、Socket、Streams等

    一.进程间通信简述 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进 ...

  7. C++和C#进程之间通过命名管道通信(上)

    C++和C#进程之间通过命名管道通信(上) "命名管道"是一种简单的进程间通信(IPC)机制.命名管道可在同一台计算机的不同进程之间,或在跨越一个网络的不同计算机的不同进程之间,支 ...

  8. 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)

    RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三  多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...

  9. Linux下进程通信之管道

    每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把 ...

随机推荐

  1. python之集合(set)学习

    集合(set) 集合是一个无序的不重复元素序列,使用大括号({}).set()函数创建集合, 注意:创建一个空集合必须用set()而不是{},因为{}是用来创建一个空字典. 集合是无序的.不重复的.没 ...

  2. STL::sort函数实现

    声明:本文参考链接:STL::sort实现. 排序是面试中经常被问及的算法基础知识点,虽然实际应用中不会直接使用,但是理解这些简单的算法知识对于更复杂更实用的算法有一定的帮助,毕竟面试总不能问的太过深 ...

  3. 课程五(Sequence Models),第二 周(Natural Language Processing & Word Embeddings) —— 0.Practice questions:Natural Language Processing & Word Embeddings

    [解释] The dimension of word vectors is usually smaller than the size of the vocabulary. Most common s ...

  4. vue内置指令与自定义指令

    一.内置指令 1.v-bind:响应并更新DOM特性:例如:v-bind:href  v-bind:class  v-bind:title  v-bind:bb 2.v-on:用于监听DOM事件: 例 ...

  5. struts转发和重定向action

    1.转发(服务器端跳转) <action name="rederTo"> <result type="chain">hello</ ...

  6. ClickHouse之clickhouse-local

    一直在慢慢的摸索clickhouse,之前是用rpm包安装的,没有发现clickhouse-local,最近在centos上面编译成功以后发现多了clickhouse-local,那么这个玩意是什么鬼 ...

  7. 【MySQL经典案例分析】 Waiting for table metadata lock

    本文由云+社区发表 一. 问题是这样来的 ​ 2018年某个周末,接到连续数据库的告警,告警信息如下: 二. 苦逼的探索过程 1.总体的思路 看到too many connection的报错信息,基本 ...

  8. Git 撤销所有未提交(Commit)的内容

    撸了好多代码,但是突然设计改了(~~o(>_<)o ~~):或者引入个第三方库,后来又发现用不着,想删掉,但文件太多了(比如几百个):那,怎么办呢,都不想了...Git 比人聪明,所以能很 ...

  9. Java并发(一)—— 使用多线程

    Java的线程机制是抢占式的,所谓的抢占式指的是每一个线程都会被分配一个指定大小的时间片,一旦这个时间片用完,就会通过上下文切换到另一个线程上去. 并发是主要是为了提高单处理器的性能.创建一个线程会有 ...

  10. [转] 使用slim3快速开发RESTful API

    本文转自:https://blog.csdn.net/u011250882/article/details/50101599 版权声明:本文为博主原创文章,转载请注明出处和作者名,尊重别人也是尊重自己 ...