命名管道问题

时间:2016-03-10 15:31:11

标签: c++ winapi named-pipes

我正在尝试学习命名管道如何工作,并创建了2个控制台来测试服务器和客户端之间的连接。客户端将向服务器发送消息,服务器将显示消息,但它不是消息,而是返回值“nullptr”,如VS的错误异常中断所示。

下面是我的代码,如果您发现我的代码有任何问题,请告诉我,我还在学习..

Server.cpp

#include "cust_ostream.hpp"
#include <Windows.h>
#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
    LPVOID buffer = NULL;
    DWORD readbyte;

    cout << "---Named Pipe Server Test---" << endl << endl;
    cout << "Creating named pipe: \\\\.\\pipe\\mypipe" << endl;

    HANDLE hPipe = CreateNamedPipeA("\\\\.\\pipe\\mypipe", PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT,
        PIPE_UNLIMITED_INSTANCES, 1024, 1024, 0, NULL);

    if (!hPipe || hPipe == INVALID_HANDLE_VALUE)
    {
        cout << "Pipe creation failed." << endl;
        return 0;
    }

    cout << "Connecting pipe to client..." << endl;

    BOOL connect = ConnectNamedPipe(hPipe, NULL);

    if (!connect)
    {
        cout << "Connect named pipe failed" << endl;
    }

    cout << "Success! Reading pipe message from client..." << endl;

    ReadFile(hPipe, buffer, sizeof(buffer), &readbyte, NULL);

    c_cout << "Pipe message = " << *(int *)buffer << endl;

    _getch();

    return 0;
}

cust_ostream.hpp

#include <Windows.h>
#include <iostream>
#include <sstream>

using namespace std;

#define endl "\n"

class cust_ostream
{
public:
    ~cust_ostream()
    {
        cout << m_buffer.str();
    }

    template <typename T>
    cust_ostream &operator<<(T const &value)
    {
        m_buffer << value;
        return *this;
    }

private:
    ostringstream m_buffer;
};

#define c_cout cust_ostream()

和我的客户

#include <Windows.h>
#include <iostream>
#include <conio.h>

using namespace std;

int main()
{
    LPVOID data;
    DWORD writebyte;

    int i = 2;

    cout << "---Named Pipe Client---" << endl << endl;
    cout << "Creating pipe file: \\\\.\\pipe\\mypipe" << endl;

    HANDLE pipe = CreateFileA("\\\\.\\pipe\\mypipe", GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

    if (!pipe || pipe == INVALID_HANDLE_VALUE)
    {
        cout << "Pipe client failed." << endl;
        return 0;
    }

    cout << "Pipe connected to server, sending data..." << endl;

    WriteFile(pipe, &i, sizeof(i), &writebyte, NULL);

    _getch();

    return 0;
}

2 个答案:

答案 0 :(得分:0)

您需要等待NamedPipe上有一个ConnectPipeReady事件。就目前而言,您正在尝试创建管道而不会实际看到它是否成功。请在此处查看命名管道的MSDN文档:https://msdn.microsoft.com/en-ca/library/windows/desktop/aa365592(v=vs.85).aspx

具体来说,这个块:

while (1) 
{ 
  hPipe = CreateFile( 
     lpszPipename,   // pipe name 
     GENERIC_READ |  // read and write access 
     GENERIC_WRITE, 
     0,              // no sharing 
     NULL,           // default security attributes
     OPEN_EXISTING,  // opens existing pipe 
     0,              // default attributes 
     NULL);          // no template file 

  // Break if the pipe handle is valid. 

  if (hPipe != INVALID_HANDLE_VALUE) 
     break; 

  // Exit if an error other than ERROR_PIPE_BUSY occurs. 

  if (GetLastError() != ERROR_PIPE_BUSY) 
  {
     _tprintf( TEXT("Could not open pipe. GLE=%d\n"), GetLastError() ); 
     return -1;
  }

  // All pipe instances are busy, so wait for 20 seconds. 

  if ( ! WaitNamedPipe(lpszPipename, 20000)) 
  { 
     printf("Could not open pipe: 20 second wait timed out."); 
     return -1;
  } 
}

此外,您不应使用#define endl "\n",请使用std::endl

答案 1 :(得分:0)

您已将缓冲区初始化为NULL,这意味着默认情况下其长度为零。现在,当您在服务器中的read函数中使用sizeof运算符(以检索服务器从客户端接收的消息)时,您要求Read函数中的sizeof运算符读取0个字节!这意味着什么都不会被阅读。

要解决此问题,您可以声明一个大小为100的字符数组或一个您确定不会被客户端超出的消息大小。就像你假设客户端的消息不会超过60个字符一样,那么你可以创建一个大小为100的char缓冲区,以确保你能够容纳客户端的所有消息。

还有一件事,如果问题仍然存在,而不是在读取中使用sizeof,请使用100或任何大小的char缓冲区数组。这应该可以解决你的问题。