命名管道实现跨语言进程通信

管道是一种进程间的通信机制,Windows 和 Linux(以及 UNIX)上都使用的这种机制。  创建管道后,通过使用操作系统的任何读或写 IO 系统调用来读或者写它。Windows 管道与 Linux 管道的区别在于 Windows 使用单一句柄(类似于 Linux 文件描述符)支持双向 IO。Linux 管道返回两个文件描述符来实现双向 IO。
Windows下有匿名管道和命名管道,匿名管道主要用于父子进程之间通信,命名管道则可以用于本机任意程序之间。Linux下的命名管道一般也被称为FIFO。
因为命名管道可以实现任意进程之间的通信,只要平台支持,不管这些进程是用哪种语言编写的,只要一方成功创建管道,另一方成功打开管道,2者就可以进行通信。
下面写了一个简单的C++类用来打开一个用于通信的管道,也就是服务端。是一个windows console程序
server.h

#include “afxwin.h ”
#include<iostream>
using namespace std;
class server
{
public:
server();
~server();
UINT createPipe(char* pipeName);
static UINT ReadProc(LPVOID lpVoid);
UINT closePipe();
private:
HANDLE m_hPipe;
HANDLE event;
};

server.cpp

#include “server.h”
server::server()
{
event=CreateEvent(NULL,FALSE,FALSE,NULL);
}
server::~server()
{
CloseHandle(event);
}
UINT server::createPipe(char* pipeName)
{
m_hPipe = CreateNamedPipe(pipeName, PIPE_ACCESS_DUPLEX, PIPE_TYPE_BYTE | PIPE_READMODE_BYTE, 1, 0, 0, 1000, NULL); // 创建命名管道
if (m_hPipe == INVALID_HANDLE_VALUE)
cout<< “create pipe failed!”;
else{
cout<< “create pipe successfully!”;

AfxBeginThread(ReadProc, this); // open thread
WaitForSingleObject(event,INFINITE); //block main thread
}
return 1;
}
UINT server::ReadProc(LPVOID lpVoid)
{
server * p=(server*)lpVoid;
char buffer[1024];
DWORD ReadNum;
if (ConnectNamedPipe(p->m_hPipe, NULL) == FALSE) // waiting for connection
{
CloseHandle(p->m_hPipe);
cout<<”connection with client failed!”;
return 0;
}
else
{
cout<< “connection with client is ok!!”;
}
// read data from pipe
if (ReadFile(p->m_hPipe, buffer, sizeof(buffer), &ReadNum, NULL) == FALSE)
{
CloseHandle(p->m_hPipe);
cout<< “read data from pipe failed!”;
}
else
{
buffer[ReadNum] = ‘/0′; ;
cout<< buffer ;
}
SetEvent(p->event); //release event
return 1;
}

UINT server::closePipe()
{
if (DisconnectNamedPipe(m_hPipe) == FALSE)
{
cout<< “close pipe failed!”;
return TRUE;
}
else
{
CloseHandle(m_hPipe);
cout<< “close pipe successfully!”;
return FALSE;
}
}

int main()
{
server mySevr;
mySevr.createPipe(”.//Pipe//Test”);
mySevr.closePipe();
return 1;
}

windows下命名管道的名称一般为//./pipe/name。管道创建成功后就可以用标准文件操作进行通信了。下面用python做例子
>>>f=open(”.//Pipe//Test”,”w”) #open pipe
>>>f.write(”hello,world”) #write data
>>>f.close() #close pipe
这样c++的服务端就可以收到“hello,world”信息了。

下面同样给出一个Linux下C++服务端类(以下代码感谢tspan提供)
duplex_fifo.h

#ifndef DUPLEX_FIFO_H_
#define DUPLEX_FIFO_H_

#include

class duplex_fifo
{
public:
duplex_fifo(const std::string& _fifo_in, const std::string& _fifo_out);
~duplex_fifo();
void run();

private:
void remove();
void create();
void init();
std::string read_fifo(std::string& str);
void write_fifo(const std::string& str);
void perform_action();

bool ok;
bool cr_in;
bool cr_out;
std::string fifo_in;
std::string fifo_out;
};

#endif /* DUPLEX_FIFO_H_ */

duplex_fifo.cpp

#include
#include
#include
#include

#include “duplex_fifo.h”

using namespace std;

duplex_fifo::duplex_fifo(const string& _fifo_in, const string& _fifo_out)
{
fifo_in = _fifo_in;
fifo_out = _fifo_out;
}

duplex_fifo::~duplex_fifo()
{
remove();
}

// remove fifos from file system
void duplex_fifo::remove()
{
int err;
ok = true;

if(cr_in)
{
// remove fifo_in file if it exists
err = ::remove(fifo_in.c_str());
if(err == -1 && errno != ENOENT)
{
cerr << “Error removing fifo_in: ” << strerror(errno) << “/n”;
ok = false;
}
}
if(cr_out)
{
// remove fifo_out file if it exists
err = ::remove(fifo_out.c_str());
if(err == -1 && errno != ENOENT)
{
cerr << “Error removing fifo_out: ” << strerror(errno) << “/n”;
ok = false;
}
}
}

// create fifo_in and fifo_out
void duplex_fifo::create()
{
int err;
cr_in = cr_out = true;

// create fifo_in
err = mkfifo(fifo_in.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if(err == -1)
{
cerr << “Could not create FIFO: ” << strerror(errno) << “/n”;
cr_in = false;
}

// create fifo_out
err = mkfifo(fifo_out.c_str(), S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
if(err == -1)
{
cerr << “Could not create FIFO: ” << strerror(errno) << “/n”;
cr_out = false;
}

ok = cr_in && cr_out;
}

// initialize fifo files
void duplex_fifo::init()
{
cr_in = cr_out = true;
ok = true;

remove();
if(!ok)
return;

create();
}

// reads string from fifo_in
string duplex_fifo::read_fifo(string& str)
{
ifstream ifs(fifo_in.c_str()); // ifstream for reading

// test ifs
if(!ifs.good()) {
cerr << “Cannot read from input stream./n”;
ok = false;
return str;
}

// read data
ifs >> str;

return str;
}

// writes string to fifo_out
void duplex_fifo::write_fifo(const string& str)
{
ok = true;

ofstream ofs(fifo_out.c_str()); // ofstream for writing

// test ofs
if(!ofs.good())
{
cerr << “Cannot write to output stream./n”;
ok = false;
return;
}

// write data
ofs << str;
}

// reads from fifo_in, writes to fifo_out
void duplex_fifo::perform_action()
{
string str;

// read string from fifo_in
read_fifo(str);
if(!ok)
return;

// terminate server
if(str.compare(”Terminate”) == 0)
{
cerr << “Terminating …/n”;
ok = false;
}
else
// write string to fifo_out
write_fifo(str);

if(!ok)
return;
}

// read data from fifo_in in a loop
void duplex_fifo::run()
{
init();
if(!ok)
return;

while(true)
{
perform_action();
if(!ok)
break;
}
}

main.cpp

#include “duplex_fifo.h”

#define FIFO_IN “/tmp/test_fifo_in”
#define FIFO_OUT “/tmp/test_fifo_out”

int main(int argc, char *argv[])
{
duplex_fifo df(FIFO_IN, FIFO_OUT);
df.run();
return 0;
}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值