Отправить многомерный массив numpy по сокету

Добрый день,

Я искал это, но не придумал никаких ответов. Я хочу отправить многомерный массив numpy через сокет. Следовательно, я решил преобразовать его в строку:

Однако он уничтожает представление массива:

>>> import numpy as np
>>> x = np.array([[0, 1], [2, 3]])
>>> xstring = x.tostring()
>>> print xstring

>>> print x
[[0 1]
 [2 3]]
>>> print xstring

>>> nparr = np.fromstring(xstring, dtype=np.uint8)
>>> print nparr
[0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 2 0 0 0 0 0 0 0 3 0 0 0 0 0 0 0]

В любом случае я могу каким-то образом преобразовать строку в строку, сохраните ее размер?

Ответ 1

Попробуйте этот пример: -

import socket
import numpy as np
from cStringIO import StringIO

class numpysocket():
    def __init__(self):
        pass

    @staticmethod
    def startServer():
        port=7555
        server_socket=socket.socket() 
        server_socket.bind(('',port))
        server_socket.listen(1)
        print 'waiting for a connection...'
        client_connection,client_address=server_socket.accept()
        print 'connected to ',client_address[0]
        ultimate_buffer=''
        while True:
            receiving_buffer = client_connection.recv(1024)
            if not receiving_buffer: break
            ultimate_buffer+= receiving_buffer
            print '-',
        final_image=np.load(StringIO(ultimate_buffer))['frame']
        client_connection.close()
        server_socket.close()
        print '\nframe received'
        return final_image

    @staticmethod
    def startClient(server_address,image):
        if not isinstance(image,np.ndarray):
            print 'not a valid numpy image'
            return
        client_socket=socket.socket()
        port=7555
        try:
            client_socket.connect((server_address, port))
            print 'Connected to %s on port %s' % (server_address, port)
        except socket.error,e:
            print 'Connection to %s on port %s failed: %s' % (server_address, port, e)
            return
        f = StringIO()
        np.savez_compressed(f,frame=image)
        f.seek(0)
        out = f.read()
        client_socket.sendall(out)
        client_socket.shutdown(1)
        client_socket.close()
        print 'image sent'
        pass

В этой модели клиент отправляет многомерный ndarray на сервер. Существуют две функции startServer() и startClient(). startServer не принимает аргументов, но startClient требует адрес сервера, а также ndarray в качестве аргументов. Сначала запустите сервер, а затем запустите клиент. Сервер начинает чтение из буфера только после получения сообщения об отключении от клиента.

Ответ 2

Действительно, .tostring возвращает только исходные данные. Это означает, что вам также необходимо отправить форму и тип массива, если они не известны с другой стороны.

Может быть, проще сериализовать массив с помощью Pickle:

import numpy as np
from cPickle import dumps, loads

x = np.array([[1, 2],[3, 4]], np.uint8)
print loads(dumps(x))
# [[1 2]
#  [3 4]]

Хотя для очень маленьких массивов размер служебных данных может быть значительным:

print len(x.tostring()), len(dumps(x))
# 4 171

Подробнее об использовании Pickle, см. здесь.

Ответ 3

Это слегка импровизированный ответ для ajsp ответа с использованием XML-RPC.

На стороне сервера, когда вы преобразуете данные, преобразуйте пустые данные в строку, используя метод .tostring(). Это кодирует numy ndarray как строку байтов. На стороне клиента, когда вы получаете данные, декодируйте их, используя метод '.fromstring()'. Я написал две простые функции для этого. Надеюсь, это полезно.

  1. ndarray2str - конвертирует numy ndarray в строку байтов.
  2. str2ndarray - преобразует двоичный str обратно в numy ndarray.
    def ndarray2str(a):
        # Convert the numpy array to string 
        a = a.tostring()

        return a

На стороне получателя данные принимаются как объект 'xmlrpc.client.Binary'. Вам необходимо получить доступ к данным с помощью.data.

    def str2ndarray(a):
        # Specify your data type, mine is numpy float64 type, so I am specifying it as np.float64
        a = np.fromstring(a.data, dtype=np.float64)
        a = np.reshape(a, new_shape)

        return a

Примечание: Единственная проблема этого подхода в том, что XML-RPC очень медленный при отправке больших массивов. Мне потребовалось около 4 секунд, чтобы отправить и получить массив данных размером (10, 500, 500, 3) для меня.

Я использую Python 3.7.4.