管道是一种进程间的通信机制,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;
}