2016-03-10 80 views
0

我想了解命名管道是如何工作的,并创建了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() 

and my client

#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; 
} 
+0

'缓冲区'为空。你从来没有给它分配过任何东西,所以'nullptr'异常正是你所期望的。分配一些内存并将其分配给“缓冲区”或仅使用预分配的数组。 –

+0

我的天哪,我错过了!感谢您指出@CareyGregory。 – ReverseEngineer

回答

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

+0

然而'nullptr'异常将会保留,因为他试图读入一个空指针。 –

+0

@坦纳,是的,我只是创建这个来看它是如何工作的,实际上这些错误检查是实现的。感谢您指出这一点:D – ReverseEngineer

0

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

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

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