2016-11-21 119 views
0

以下代碼是較大軟件包的片段。我想了解代碼如何管理像numpy數組,單元格這樣的對象。我想知道的是,代碼似乎沒有序列化對象,但它確實有效。它爲什麼有效?通過Python中的套接字發送對象到C/Fortran

Python客戶機代碼(片斷):

class DriverSocket(socket.socket): 

    def __init__(self, _socket_interface): 
     super(DriverSocket,self).__init__(_sock=_socket_interface) 


    def sendpos(self, pos, cell): 
     """Sends the position and cell data to the driver. 

     Args: 
     pos: An array containing the atom positions. 
     cell: A cell object giving the system box. 

     Raises: 
     InvalidStatus: Raised if the status is not Ready. 
     """ 

     if (self.status & Status.Ready): 
     try: 
      self.sendall(Message("posdata")) 
      self.sendall(cell.h) 
      self.sendall(cell.ih) 
      self.sendall(np.int32(len(pos)/3)) 
      self.sendall(pos) 
     except: 
      self.poll() 
      return 
     else: 
     raise InvalidStatus("Status in sendpos was " + self.status) 

用C接收代碼(片斷):

void open_socket_(int *psockfd, int* inet, int* port, char* host) 
/* Opens a socket. 

Note that fortran passes an extra argument for the string length, but this is 
ignored here for C compatibility. 

Args: 
    psockfd: The id of the socket that will be created. 
    inet: An integer that determines whether the socket will be an inet or unix 
     domain socket. Gives unix if 0, inet otherwise. 
    port: The port number for the socket to be created. Low numbers are often 
     reserved for important channels, so use of numbers of 4 or more digits is 
     recommended. 
    host: The name of the host server. 
*/ 

{ 
    int sockfd, portno, n; 
    struct hostent *server; 

    struct sockaddr * psock; int ssock; 

    if (*inet>0) 
    { // creates an internet socket 
     struct sockaddr_in serv_addr;  psock=(struct sockaddr *)&serv_addr;  ssock=sizeof(serv_addr); 
     sockfd = socket(AF_INET, SOCK_STREAM, 0); 
     if (sockfd < 0) error("Error opening socket"); 

     server = gethostbyname(host); 
     if (server == NULL) 
     { 
     fprintf(stderr, "Error opening socket: no such host %s \n", host); 
     exit(-1); 
     } 

     bzero((char *) &serv_addr, sizeof(serv_addr)); 
     serv_addr.sin_family = AF_INET; 
     bcopy((char *)server->h_addr, (char *)&serv_addr.sin_addr.s_addr, server->h_length); 
     serv_addr.sin_port = htons(*port); 
     if (connect(sockfd, psock, ssock) < 0) error("Error opening socket: wrong host address, or broken connection"); 
    } 
    else ... 



void readbuffer_(int *psockfd, char *data, int* plen) 
/* Reads from a socket. 

Args: 
    psockfd: The id of the socket that will be read from. 
    data: The storage array for data read from the socket. 
    plen: The length of the data in bytes. 
*/ 

{ 
    int n, nr; 
    int sockfd=*psockfd; 
    int len=*plen; 

    n = nr = read(sockfd,data,len); 

    while (nr>0 && n<len) 
    { nr=read(sockfd,&data[n],len-n); n+=nr; } 

    if (n == 0) error("Error reading from socket: server has quit or connection broke"); 
} 

然後是其中所用的C-插座代碼Fortran代碼

CALL open_socket(socket, inet, port, host) 
... 
CALL readbuffer(socket, msgbuffer, nat*3*8) 

而這個接收代碼確實得到了一個二維數組,等等。同樣的作品在相反的方向。

回答

0

如果您嘗試通過send/sendall發送任意對象,您將看到一個異常,表示類似於字節。所以這個想法很簡單,你發送的numpy結構提供類似字節的接口,轉換爲字節只留下原始的二進制數據。

最簡單的實現是從bytes繼承:

class A: pass 
sock.sendall(A()) # exception 

class B(bytes): pass 
sock.sendall(B()) # no exception 

然而,numpy的是用Python寫的,用Cython和C.他們可以使用C API提供類似的功能一個複雜的框架。

這也是值得注意的是,因爲我希望鴨打字不在這裏工作:

class C: 
    def __bytes__(self): 
     return bytes() 

sock.sendall(C()) # exception 
+0

謝謝您的回答。你的意思是你預計鴨子打字會不會起作用?另外,我編寫了一個小的示例python代碼,其中接收者和發件人是一個python套接字,併發送了一些numpy數組。它的工作,但收到的數據沒有恢復,我得到▯▯作爲收到的數據的價值。 – Jadzia

+0

@Jadzia我希望鴨子打字工作。至於你的示例代碼,我認爲如果你感興趣,最好發表另一個問題。可能並非所有numpy的內容都可以通過網絡「按原樣」發送。也有可能發送接收中存在不正確的內容,但我不敢堅持,因爲我沒有看到代碼。 – Vovanrock2002

+0

send/sendall需要一個實現緩衝協議API的「類字節」對象。目前緩衝協議只能在C中實現。這就是爲什麼你可以發送像'array.array'和'numpy.array'和'memoryview'這樣的東西,它不能從'bytes'繼承,但是要實現C API。有一個公開票證允許緩衝協議的純Python實現,但它是低優先級的(已經開放了近5年)。 https://bugs.python.org/issue13797 – Dunes