2012-03-15 160 views
5

我有应用程序服务器(server.py)和C++作为客户端(client.exe)。 Client.exe通过'命名管道'将变量发送到server.py。C++与Python之间的通信(IPC)

问题是,当我发送如server.py中client.exe的“默认消息来自客户端”只产生“D”(只有第一个字符发送)。

任何人都可以帮助我?

C++

server.py

from ctypes import * 

PIPE_ACCESS_DUPLEX = 0x3 
PIPE_TYPE_MESSAGE = 0x4 
PIPE_READMODE_MESSAGE = 0x2 
PIPE_WAIT = 0 
PIPE_UNLIMITED_INSTANCES = 255 
BUFSIZE = 4096 
NMPWAIT_USE_DEFAULT_WAIT = 0 
INVALID_HANDLE_VALUE = -1 
ERROR_PIPE_CONNECTED = 535 

MESSAGE = "Default answer from server\0" 
szPipename = "\\\\.\\pipe\\mynamedpipe" 


def ReadWrite_ClientPipe_Thread(hPipe): 
    chBuf = create_string_buffer(BUFSIZE) 
    cbRead = c_ulong(0) 
    while 1: 
     fSuccess = windll.kernel32.ReadFile(hPipe, chBuf, BUFSIZE, 
byref(cbRead), None) 
     if ((fSuccess ==1) or (cbRead.value != 0)): 
      print chBuf.value 
      cbWritten = c_ulong(0) 
      fSuccess = windll.kernel32.WriteFile(hPipe,c_char_pc_char_p(MESSAGE),len(MESSAGE),byref(cbWritten),None) 
     else: 
      break 
     if ((not fSuccess) or (len(MESSAGE) != cbWritten.value)): 
      print "Could not reply to the client's request from the pipe" 
      break 
     else: 
      print "Number of bytes written:", cbWritten.value 

    windll.kernel32.FlushFileBuffers(hPipe) 
    windll.kernel32.DisconnectNamedPipe(hPipe) 
    windll.kernel32.CloseHandle(hPipe) 
    return 0 

def main(): 
    THREADFUNC = CFUNCTYPE(c_int, c_int) 
    thread_func = THREADFUNC(ReadWrite_ClientPipe_Thread) 
    while 1: 
     hPipe = windll.kernel32.CreateNamedPipeA(szPipename,PIPE_ACCESS_DUPLEX,PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, BUFSIZE, BUFSIZE, NMPWAIT_USE_DEFAULT_WAIT,None) 
     if (hPipe == INVALID_HANDLE_VALUE): 
      print "Error in creating Named Pipe" 
      return 0 

     fConnected = windll.kernel32.ConnectNamedPipe(hPipe, None) 
     if ((fConnected == 0) and (windll.kernel32.GetLastError() == ERROR_PIPE_CONNECTED)): 
      fConnected = 1 
     if (fConnected == 1): 
      dwThreadId = c_ulong(0) 
      hThread = windll.kernel32.CreateThread(None, 0, thread_func, hPipe, 0, byref(dwThreadId)) 
      if (hThread == -1): 
       print "Create Thread failed" 
       return 0 
      else: 
       windll.kernel32.CloseHandle(hThread) 
     else: 
      print "Could not connect to the Named Pipe" 
      windll.kernel32.CloseHandle(hPipe) 
    return 0 


if __name__ == "__main__": 
    main() 

Client.cpp

#include "stdafx.h" 
#include <windows.h> 
#include <stdio.h> 
#include <conio.h> 
#include <tchar.h> 

#define BUFSIZE 512 

int _tmain(int argc, TCHAR *argv[]) 
{ 
    HANDLE hPipe; 
    LPTSTR lpvMessage=TEXT("Default message from client."); 
    TCHAR chBuf[BUFSIZE]; 
    BOOL fSuccess = FALSE; 
    DWORD cbRead, cbToWrite, cbWritten, dwMode; 
    LPTSTR lpszPipename = TEXT("\\\\.\\pipe\\mynamedpipe"); 

    if(argc > 1) 
     lpvMessage = argv[1]; 

// Try to open a named pipe; wait for it, if necessary. 

    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; 
     } 
    } 

// The pipe connected; change to message-read mode. 

    dwMode = PIPE_READMODE_MESSAGE; 
    fSuccess = SetNamedPipeHandleState( 
     hPipe, // pipe handle 
     &dwMode, // new pipe mode 
     NULL,  // don't set maximum bytes 
     NULL); // don't set maximum time 
    if (! fSuccess) 
    { 
     _tprintf(TEXT("SetNamedPipeHandleState failed. GLE=%d\n"), GetLastError()); 
     return -1; 
    } 

// Send a message to the pipe server. 

    cbToWrite = (lstrlen(lpvMessage)+1)*sizeof(TCHAR); 
    _tprintf(TEXT("Sending %d byte message: \"%s\"\n"), cbToWrite, lpvMessage); 

    fSuccess = WriteFile( 
     hPipe,     // pipe handle 
     lpvMessage,    // message 
     cbToWrite,    // message length 
     &cbWritten,    // bytes written 
     NULL);     // not overlapped 

    if (! fSuccess) 
    { 
     _tprintf(TEXT("WriteFile to pipe failed. GLE=%d\n"), GetLastError()); 
     return -1; 
    } 

    printf("\nMessage sent to server, receiving reply as follows:\n"); 

    do 
    { 
    // Read from the pipe. 

     fSuccess = ReadFile( 
     hPipe, // pipe handle 
     chBuf, // buffer to receive reply 
     BUFSIZE*sizeof(TCHAR), // size of buffer 
     &cbRead, // number of bytes read 
     NULL); // not overlapped 

     if (! fSuccess && GetLastError() != ERROR_MORE_DATA) 
     break; 

     _tprintf(TEXT("\"%s\"\n"), chBuf); 
    } while (! fSuccess); // repeat loop if ERROR_MORE_DATA 

    if (! fSuccess) 
    { 
     _tprintf(TEXT("ReadFile from pipe failed. GLE=%d\n"), GetLastError()); 
     return -1; 
    } 



    CloseHandle(hPipe); 

    return 0; 
} 

回答

-1

也许服务器应该尝试在一个循环从管道读,直到所有数据你期望达到,已达到(根据你的协议与客户,例如直到空三分子被读出)。

+0

只有当我用两种不同的语言运行时才会发生这种情况。但是在python和C++中使用相同的语言都运行得很好 – Varanka 2012-03-16 01:23:01

+0

@Varanka也许在读取中的缓冲是不同的。我认为直到读取所有期望的数据(或者到达EOF - 管道关闭)为止,读取会更加正确。 – selalerer 2012-03-16 12:18:16

3

如果打印出来的。RAW由服务器接收到的缓冲,你可以看到它实际上是让整个消息:

> print repr(chBuf.raw) 

'D\x00e\x00f\x00a\x00u\x00l\x00t\x00 \x00m\x00e\x00s\x00s\x00a\x00g\x00e\x00 \x00f\x00r\x00o\x00m\x00\x00c\x00l\x00i\x00e\x00n\x00t\x00.\x00\x00\x00\x00\x00 ... \x00\x00' 

的问题是,还有空值(\ X00)之间穿插合法的字符,当你试图打印chBuf.value时,它们看起来像空终止符。那么为什么所有的空值?这是因为您的C++客户端正在发送wchar_t *消息(使用LPTSTR),但是Python服务器期待char *字符串。

改变这一行:

chBuf = create_string_buffer(BUFSIZE) 

这样:

chBuf = create_unicode_buffer(BUFSIZE) 

这应该可以解决这个问题。

哦也,看起来你有一个复制和粘贴错误的位置:

fSuccess = windll.kernel32.WriteFile(hPipe,c_char_pc_char_p(MESSAGE),len(MESSAGE),byref(cbWritten),None) 

它应该是:

fSuccess = windll.kernel32.WriteFile(hPipe, c_char_p(MESSAGE),len(MESSAGE),byref(cbWritten),None) 

我在Python代码名称错误,直到我改变了。

+1

更具体地说,Windows TEXT()宏将生成ANSI或UTF-16字符串,具体取决于UNICODE是否被#defined。 请参阅http://msdn.microsoft.com/en-us/library/windows/desktop/dd374074(v=vs.85).aspx – 2012-04-19 04:16:19

+0

不错!因此,有一种方法可以在C++端或Python端修复代码:) – NattyBumppo 2012-04-20 15:29:56