2012-03-15 39 views
5

Tôi có máy chủ ứng dụng (server.py) và C + + làm ứng dụng khách (client.exe). Client.exe gửi biến đến server.py thông qua 'pipe named'.Giao tiếp (IPC) giữa C++ với Python

Vấn đề là khi tôi gửi ví dụ: "Thông báo mặc định từ ứng dụng khách" từ client.exe trong server.py chỉ tạo "D" (chỉ gửi ký tự đầu tiên).

Có ai có thể giúp tôi không ??

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

Trả lời

-1

Có lẽ máy chủ nên cố gắng đọc từ các đường ống trong một vòng lặp cho đến khi tất cả các dữ liệu mà bạn mong đợi đạt được, đã đạt được (theo giao thức của bạn với khách hàng, ví dụ như cho đến khi một ter ter minator đã được đọc).

+0

Điều này chỉ xảy ra khi tôi chạy bằng hai ngôn ngữ khác nhau. Nhưng với cùng một ngôn ngữ trong cả hai trăn và c + + đều chạy tốt – Varanka

+0

@Varanka Có lẽ việc đệm trong đọc là khác nhau. Tôi nghĩ rằng nó sẽ được chính xác hơn để đọc cho đến khi tất cả các dữ liệu dự kiến ​​được đọc (hoặc EOF đạt - ống đã được đóng lại). – selalerer

3

Nếu bạn in ra .raw cho bộ đệm nhận bởi máy chủ, bạn có thể thấy nó thực sự nhận được toàn bộ thông điệp:

> 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' 

Vấn đề là có giá trị null (\ x00) xen kẽ giữa các ký tự hợp pháp và các ký tự giống như các terminator null khi bạn đang cố gắng in chBuf.value. Vậy tại sao tất cả các null? Điều này là do máy khách C++ của bạn đang gửi một thông báo wchar_t * (sử dụng LPTSTR), nhưng máy chủ Python đang mong đợi một chuỗi char *.

Thay đổi dòng này:

chBuf = create_string_buffer(BUFSIZE) 

này:

chBuf = create_unicode_buffer(BUFSIZE) 

này cần khắc phục vấn đề.

Oh, cũng được, có vẻ như bạn có một lỗi sao chép và dán ở đây:

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

nó nên là:

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

tôi nhận được một lỗi tên trong mã Python cho đến khi tôi đã thay đổi điều đó.

+1

Cụ thể hơn, macro Windows TEXT() sẽ tạo ra một chuỗi ANSI hoặc UTF-16, tùy thuộc vào việc UNICODE có được định nghĩa #defined hay không. Xem http://msdn.microsoft.com/en-us/library/windows/desktop/dd374074(v=vs.85).aspx –

+0

Tốt! Vì vậy, có một cách để sửa mã ở phía bên C++ hoặc bên Python :) – NattyBumppo

Các vấn đề liên quan