2016-03-10 79 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緩衝區數組的大小。這應該可以解決你的問題。