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

    java基础-2 面向对象 定义 面向对象是一种思维方式,相对于面向过程​面向过程注重流程中的每一步,清楚流程中的每一个细节​面向对象注重的是对象,有了对象就有对象的一届​自己动手做--面向过程,找其 ...

  2. JSON库的使用研究(一)

    最近用到JSON,收集了一些资料,整理如下: 选择一个合适的JSON库要从多个方面进行考虑: 字符串解析成JSON性能 字符串解析成Java Object性能 Java Object转JSON性能 集 ...

  3. Vue -- 基础语法和使用

    Vue 渐进式 JavaScript 框架 通过对框架的了解与运用程度,来决定其在整个项目中的应用范围,最终可以独立以框架方式完成整个web前端项目 一.走进Vue 1.what -- 什么是Vue ...

  4. 小程序this.setData

    data: { isChecked: [ { key: true },{ key: true },{ key: true} ]} 如上,如果我想动态修改isChecked里面指定某个下标的值怎么办? ...

  5. leetcode — trapping-rain-water

    /** * Source : https://oj.leetcode.com/problems/trapping-rain-water/ * * Created by lverpeng on 2017 ...

  6. 关于JBoss7.X修改post传输数据量(max-post-size)的问题

    转自: https://blog.csdn.net/zhangyunhao108/article/details/53140569 JBoss7.X修改max-post-size在网上百度了好久,都不 ...

  7. 日志切割工具logrotate解决Tomcat catalina.out日志过大的问题

    一.介绍日志切割logrotate 对于Linux系统安全来说,日志文件是极其重要的工具.不知为何,我发现很多运维同学的服务器上都运行着一些诸如每天切分Nginx日志之类的CRON脚本,大家似乎遗忘了 ...

  8. 【Go】strings.Replace 与 bytes.Replace 调优

    原文链接:https://blog.thinkeridea.com/201902/go/replcae_you_hua.html 标准库中函数大多数情况下更通用,性能并非最好的,还是不能过于迷信标准库 ...

  9. OOP面向对象

    一:什么是面向过程 我们是怎么思考和解决上面的问题呢? 答案是:我们自己的思维一直按照步骤来处理这个问题,这是我们的常规思维,这就是所谓的面向过程POP编程   二:面向过程POP为什么转换为OOP ...

  10. 操作数据库出现InvalidOpertionException(内部连接致命错误)

    用DataTables时并发访问量较大,单个任务操作(获取数据)时间较长.连接数过多的时候就出现InvalidOpertionException错误.知道哪里有问题那就好办了,对GetDataTabl ...