2016-11-21 86 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