操作系统-进程通信(信号量、匿名管道、命名管道、Socket)
进程通信(信号量、匿名管道、命名管道、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)的更多相关文章
- 邮槽 匿名管道 命名管道 剪贴板 进程通讯 转自http://www.cnblogs.com/kzloser/archive/2012/11/04/2753367.html#
邮槽 通信流程: 服务器 客户端 注意: 邮槽是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输 邮槽可以实现一对多的单向通信,我们可以利用这个特点编写一个网络会议通知系统,而且实现这一的系 ...
- Linux进程通信之匿名管道
进程间的通信方式 进程间的通信方式包括,管道.共享内存.信号.信号量.消息队列.套接字. 进程间通信的目的 进程间通信的主要目的是:数据传输.数据共享.事件通知.资源共享.进程控制等. 进程间通信之管 ...
- C#命名管道通信
C#命名管道通信 最近项目中要用c#进程间通信,以前常见的方法包括RMI.发消息等.但在Windows下面发消息需要有窗口,我们的程序是一个后台运行程序,发消息不试用.RMI又用的太多了,准备用管道通 ...
- c# c++通信--命名管道通信
进程间通信有很多种,windows上面比较简单的有管道通信(匿名管道及命名管道) 最近做个本机c#界面与c++服务进行通信的一个需求.简单用命名管道通信.msdn都直接有demo,详见下方参考. c+ ...
- [转]WINDOW进程通信的几种方式
windows进程通信的几种方式 1 文件映射 文件映射(Memory-Mapped Files)能使进程把文件内容当作进程地址区间一块内存那样来对待.因此,进程不必使用文件I/O操作,只需简单的指针 ...
- 【windows 操作系统】进程间通信(IPC)简述|无名管道和命名管道 消息队列、信号量、共享存储、Socket、Streams等
一.进程间通信简述 每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进 ...
- C++和C#进程之间通过命名管道通信(上)
C++和C#进程之间通过命名管道通信(上) "命名管道"是一种简单的进程间通信(IPC)机制.命名管道可在同一台计算机的不同进程之间,或在跨越一个网络的不同计算机的不同进程之间,支 ...
- 【LINUX/UNIX网络编程】之使用消息队列,信号量和命名管道实现的多进程服务器(多人群聊系统)
RT,使用消息队列,信号量和命名管道实现的多人群聊系统. 本学期Linux.unix网络编程的第三个作业. 先上实验要求: 实验三 多进程服务器 [实验目的] 1.熟练掌握进程的创建与终止方法: 2 ...
- Linux下进程通信之管道
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把 ...
随机推荐
- 设置python环境变量
原始环境变量 /> python Python |Anaconda (-bit)| (default, May , ::) [GCC (Red Hat -)] on linux Type &qu ...
- sql server 日志文件结构及误操作数据找回
一. 概述 在sql server 里有数据文件.mdf和日志文件.ldf,日志文件是sqlserver数据库的另一个重要组成部分,日志文件记录了所有事务以及每个事务对数据库所做的修改.为了提高数据库 ...
- Java 容器 & 泛型:六、容器讲到为什么要使用泛型
Writer:BYSocket(泥沙砖瓦浆木匠) 微博:BYSocket 豆瓣:BYSocket ArrayList是集合类中无处不在的,泛型也是,泛型对集合类尤其有用.但是为啥要使用泛型?理解好了这 ...
- 浅谈《think in java》:一 对象导论总结
清单1. 抽象机制,面向对象程序设计方式 java所基于Smalltalk的特性表现一种纯粹的面向对象设计方式: 万物都是对象 程序是对象的集合(容器),他们通过发送消息(发送请求)来告知彼此所要做的 ...
- solr(五): centos中, 整合 tomcat&solr
前言 虽然windows下, tomcat和solr整合起来灰常的方便, 但是, 一般像这种东西, 都很少部署在windows中, 更多的是部署到linux中去. 其实, 步骤是一样的, 这里, 我在 ...
- 【原创】uC/OS II 任务切换原理
今天学习了uC/OS II的任务切换,知道要实现任务的切换,要将原先任务的寄存器压入任务堆栈,再将新任务中任务堆栈的寄存器内容弹出到CPU的寄存器,其中的CS.IP寄存器没有出栈和入栈指令,所以只能引 ...
- shell脚本--cut命令
bash&shell系列文章:http://www.cnblogs.com/f-ck-need-u/p/7048359.html 1.1 选项说明 cut命令将行按指定的分隔符分割成多列,它的 ...
- PPP中的PAP和CHAP的区别
PAP PAP是简单认证,明文传送,客户端直接发送包含用户名/口令的认证请求,服务器端处理并回应. CHAP CHAP是加密认证,先由服务器端给客户端发送一个随机码 challenge,客户端根据 c ...
- Python系列:三、流程控制循环语句--技术流ken
Python条件语句 Python条件语句是通过一条或多条语句的执行结果(True或者False)来决定执行的代码块. 可以通过下图来简单了解条件语句的执行过程: Python程序语言指定任何非0和非 ...
- Bootstrap-table使用总结(整合版)
一.什么是Bootstrap-table? 在业务系统开发中,对表格记录的查询.分页.排序等处理是非常常见的,在Web开发中,可以采用很多功能强大的插件来满足要求,且能极大的提高开发效率,本随笔介绍这 ...