Named pipeのラッパ作った
template<typename T=void> struct WinResult { WinResult<T>() { success=false; error=::GetLastError(); } WinResult<T>(BOOL res,T val) { if(res) {success=true;value=val;} else {success=false;error=::GetLastError();} } WinResult(const WinResult& rhs):success(rhs.success),error(rhs.error),value(rhs.value) {} operator bool() {return success;} bool success; DWORD error; T value; }; template<> struct WinResult<void> { WinResult(BOOL res) { if(res) {success=true;} else {success=false;error=::GetLastError();} } WinResult(const WinResult& rhs):success(rhs.success),error(rhs.error) {} operator bool() {return success;} bool success; DWORD error; }; class WinError { public: WinError(DWORD err):error(err) {} WinError() {error=::GetLastError();} DWORD error; }; class NamedPipeWrapper { public: NamedPipeWrapper(HANDLE h) : m_handle(h) {} WinResult<std::string> Read() { const int bufsize=1024; char buf[bufsize]; DWORD read_bytes; std::string result; while(!::ReadFile(m_handle,buf,bufsize,&read_bytes,0)) { if(GetLastError() != ERROR_MORE_DATA) return WinResult<std::string>(); result.append(buf,read_bytes); } result.append(buf,read_bytes); return WinResult<std::string>(true,result); } WinResult<> Write(std::string content) { DWORD writen_bytes; return ::WriteFile(m_handle,content.c_str(),content.length()+1,&writen_bytes,0); } WinResult<> Flush() { return ::FlushFileBuffers(m_handle); } void Close() { Challange( ::CloseHandle(m_handle) ); } bool IsValid() { return m_handle != INVALID_HANDLE_VALUE; } ~NamedPipeWrapper() { Disconnect(); Close(); } // ================= for server ================= WinResult<> Connect() { return ::ConnectNamedPipe(m_handle,0); } void Disconnect() { Challange( ::DisconnectNamedPipe(m_handle) ); } private: NamedPipeWrapper(const NamedPipeWrapper &rhs){} void Challange(BOOL success) { if(THROW_ON_ERROR && !success) throw WinError(); } HANDLE m_handle; const static bool THROW_ON_ERROR=false; };
ほんのちょっとコーディングが楽になった。
使用例(クライアント):
int _tmain(int argc, _TCHAR* argv[]) { NamedPipeWrapper pipe(CreateFile( L"\\\\.\\pipe\\my_named_pipe", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL)); if(!pipe.IsValid()) { cerr << "couldn't open pipe" << endl; return -1; } //send msg string msg; while(msg!="exit") { getline(cin,msg); WinResult<> res=pipe.Write(msg); pipe.Flush(); //flushすると相手が受信するまでブロックする(明示的にflushしないとバッファがいっぱいになるまでブロックしない) if(!res) { if(res.error==ERROR_PIPE_NOT_CONNECTED) { cout << "disconnected." << endl; break; } cerr << "WriteFile failed:" << GetLastError() << endl; break; } } pipe.Flush(); pipe.Close(); return 0; }
サーバサイド:
int _tmain(int argc, _TCHAR* argv[]) { NamedPipeWrapper pipe( CreateNamedPipe(L"\\\\.\\pipe\\my_named_pipe", PIPE_ACCESS_DUPLEX, 0, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_NOWAIT, 1, 1024, NMPWAIT_NOWAIT, NULL) ); if(!pipe.IsValid()) { cerr << "failed create pipe" << endl; return -1; } bool quit=false; while(!quit) { cout << "wait for client..." << endl; while(1) { //wait for connect WinResult<> res=pipe.Connect(); if(!res && res.error==ERROR_PIPE_CONNECTED) break; } cout << "connected." << endl; while(1) { WinResult<string> res=pipe.Read(); if(!res) { if(res.error == ERROR_BROKEN_PIPE) { cout << "disconnected." << endl; break; } cerr << "ReadFile() failed." << endl; break; } if(res.value=="server_exit") {quit=true;break;} cout << res.value << endl; } pipe.Disconnect(); } pipe.Close(); return 0; }
汚いソースだ しかし修正する気はない