2012-03-15 12 views
5

Mam serwer aplikacji (server.py) i C++ jako klienta (client.exe). Client.exe wysyła zmienną do serwera server.py za pośrednictwem "nazwanych potoków".Komunikuj się (IPC) między C++ i Pythonem

Problem polega na tym, że podczas wysyłania np. "Domyślna wiadomość od klienta" z klienta.exe w server.py powstaje tylko "D" (tylko wysyłanie pierwszego znaku).

Czy ktoś może mi pomóc?

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

Odpowiedz

-1

Może serwer powinien próbować czytać z rury w pętli aż do wszystkich danych, które spodziewasz się osiągnąć, osiągnął (zgodnie z protokołem z klientem, np. do momentu zerowego ter minator został odczytany).

+0

Zdarza się to tylko wtedy, gdy używam dwóch różnych języków. Ale z tym samym językiem zarówno w python i C++ są zarówno działa dobrze – Varanka

+0

@Varanka Może buforowanie w czytaniu jest inna. Myślę, że czytanie będzie bardziej poprawne, dopóki wszystkie oczekiwane dane nie zostaną odczytane (lub EOF zostanie osiągnięty - rura została zamknięta). – selalerer

3

Jeśli wydrukować .raw do bufora odbieranego przez serwer widać to rzeczywiście coraz całą wiadomość:

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

Problemem jest to, że istnieją wartości null (\ x00) przeplatane między uprawnione postacie, a te wyglądają jak terminatory kończące, gdy próbujesz wydrukować wartość chBuf.value. Dlaczego wszystkie wartości zerowe? Dzieje się tak, ponieważ twój klient C++ wysyła wiadomość wchar_t * (używając LPTSTR), ale serwer Pythona oczekuje ciągu znaków *.

Zmiana ta linia:

chBuf = create_string_buffer(BUFSIZE) 

do tego:

chBuf = create_unicode_buffer(BUFSIZE) 

To powinno rozwiązać problem.

Och, także wygląda jak masz błąd kopiowania i wklejania tutaj:

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

powinny to być:

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

Dostałem błąd nazwy w kodzie Pythona, dopóki nie zmienił to.

+1

Mówiąc dokładniej, makro Windows TEXT() wygeneruje ciąg ANSI lub UTF-16, w zależności od tego, czy UNICODE jest #zdefiniowane. Zobacz http://msdn.microsoft.com/en-us/library/windows/desktop/dd374074(v=vs.85).aspx –

+0

Nice! Jest więc sposób na naprawienie kodu po stronie C++ lub po stronie Pythona :) – NattyBumppo

Powiązane problemy