2012-03-15 23 views
5

Tengo el servidor de aplicaciones (server.py) y C + + como cliente (client.exe). Client.exe envía variables a server.py a través de 'named pipes'.Comunicar (IPC) entre C++ a Python

El problema es cuando envío, por ejemplo, "Mensaje predeterminado del cliente" de client.exe en server.py solo produce "D" (solo el primer carácter de envío).

¿Alguien me puede ayudar?

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

Respuesta

-1

Tal vez el servidor debe intentar la lectura de la tubería en un bucle hasta que todos los datos que espera alcanzar, ha alcanzado (de acuerdo con su protocolo con el cliente, por ej., hasta un null ter minador fue leído).

+0

Esto ocurre solo cuando uso dos idiomas diferentes. Pero con el mismo lenguaje tanto en python como en c + + funcionan bien – Varanka

+0

@Varanka Quizás el almacenamiento en memoria intermedia en la lectura sea diferente. Creo que aún será más correcto leer hasta que se lean todos los datos esperados (o se alcance EOF - se cerró la tubería). – selalerer

3

Si imprime el .raw para el búfer recibido por el servidor se puede ver que en realidad está recibiendo todo el mensaje:

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

El problema es que hay valores nulos (\ x00) intercalados entre el personajes legítimos, y esos parecen terminadores nulos cuando intenta imprimir chBuf.value. Entonces, ¿por qué todos los nulos? Esto se debe a que su cliente C++ está enviando un mensaje wchar_t * (usando LPTSTR), pero el servidor Python espera una cadena char *.

cambiar esta línea:

chBuf = create_string_buffer(BUFSIZE) 

a esto:

chBuf = create_unicode_buffer(BUFSIZE) 

Esto debería solucionar el problema.

Ah, también, parece que tiene un error de copia y pegar aquí:

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

que debe ser:

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

Tengo un error de nombre en el código Python hasta que cambió eso.

+1

Más específicamente, la macro Windows TEXT() producirá una cadena ANSI o UTF-16, dependiendo de si UNICODE está #defined. Ver http://msdn.microsoft.com/en-us/library/windows/desktop/dd374074(v=vs.85).aspx –

+0

¡Agradable! Entonces, hay una forma de arreglar el código, ya sea en el lado de C++ o en el lado de Python :) – NattyBumppo

Cuestiones relacionadas