Как отправить байты из Python в Java с помощью сокетов? - PullRequest
0 голосов
/ 30 июня 2018

Я прочитал несколько постов о том, как отправить изображение с помощью сокетов в Python и как отправить изображение с помощью сокетов в Java, я хотел объединить их и отправить изображение из Python в Java с помощью сокетов на оба конца. Большая часть моего кода взята из сообщений, которые я прочитал, но вот клиент Python:

import socket

s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

s.connect(("192.168.0.12",4141))

try:

    file = open("subbed.jpg", 'rb')
    bytes = file.read()
    print "{0:b}".format(len(bytes))
    size = len(bytes)
    s.sendall(size)

    answer = s.recv(4096)
    print "Answer = %s" %answer 

    if answer == 'GOT SIZE':
        s.sendall(bytes)

        answer = s.recv(4096)

        if answer == 'GOT IMAGE' :
            s.sendall("byte")
    file.close()
finally:
    s.close()

код для сервера Java:

public static void main(String[] args) {
    while(true) {
        try (
                ServerSocket server = new ServerSocket(PORT_NUMBER);
                Socket client = server.accept();
                PrintWriter out = new PrintWriter(client.getOutputStream(), true);
                InputStream in = client.getInputStream()) {
            System.out.println("GOT CONNECTION FROM: " + client.getInetAddress().toString());
            byte[] sizeAr = new byte[4];

            in.read(sizeAr);
            int size = ByteBuffer.wrap(sizeAr).asIntBuffer().get();
            System.out.println(Integer.toBinaryString(size));
            out.println("GOT SIZE");

            byte[] imageAr = new byte[size];
            in.read(imageAr);

            BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageAr));
            ImageIO.write(image, "jpg", new File("C:\\myprivatelocation\\test.jpg"));

        } catch (Exception ioe) {
            ioe.printStackTrace();
        }
    }
}

Первоначальная проблема заключается в отправке размера, я думаю Я не эксперт по Python и не эксперт по Java, но я думаю, что происходит то, что Python отправляет размер в виде строки, а Java получает его в виде байтового массива и преобразует его в целое число, и есть некоторые различия в как они хранятся на двух языках. Кто-нибудь может предложить какую-либо помощь в этом вопросе?

Ответы [ 2 ]

0 голосов
/ 30 июня 2018

Хотя я бы подошел к вашей проблеме немного по-другому, работает следующий код:

Отправитель Python

import socket

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect(("127.0.0.1", 8888))

    with open("C:\\temp\\test-input.jpg", 'rb') as f:
        content = f.read()

    size = len(content)
    print("File bytes:", size)
    s.sendall(size.to_bytes(4, byteorder='big'))

    buff = s.recv(4)
    resp = int.from_bytes(buff, byteorder='big')
    print("Response:", resp)

    if size == resp:
        s.sendall(content)

    buff = s.recv(2)
    print(buff)

print("Complete.")

Приемник Java

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.ByteBuffer;


import javax.imageio.ImageIO;

class Server{
    public static void main(String[] args) {
        int PORT_NUMBER = 8888;

        try (
            ServerSocket server = new ServerSocket(PORT_NUMBER);
            Socket client = server.accept();
            OutputStream sout = client.getOutputStream();
            InputStream sin = client.getInputStream();
        ){
            System.out.println("GOT CONNECTION FROM: " + client.getInetAddress().toString());

            // Get length
            byte[] size_buff = new byte[4];
            sin.read(size_buff);
            int size = ByteBuffer.wrap(size_buff).asIntBuffer().get();
            System.out.format("Expecting %d bytes\n", size);

            // Send it back (?)
            sout.write(size_buff);

            // Create Buffers
            byte[] msg_buff = new byte[1024];
            byte[] img_buff = new byte[size];
            int img_offset = 0;
            while(true) {
                int bytes_read = sin.read(msg_buff, 0, msg_buff.length);
                if(bytes_read == -1) { break; }

                // Copy bytes into img_buff
                System.arraycopy(msg_buff, 0, img_buff, img_offset, bytes_read);
                img_offset += bytes_read;
                System.out.format("Read %d / %d bytes...\n", img_offset, size);

                if(img_offset >= size) { break; }
            }
            BufferedImage image = ImageIO.read(new ByteArrayInputStream(img_buff));
            ImageIO.write(image, "jpg", new File("C:\\temp\\test-output.jpg"));

            // Send "OK"
            byte[] OK = new byte[] {0x4F, 0x4B};
            sout.write(OK);
        }
        catch (IOException ioe) { ioe.printStackTrace(); }
    }
}

Отправитель открывает сокет, читает файл и отправляет получателю длину. Получатель получает длину, анализирует байты и отправляет ее обратно. После получения «подтверждения» отправитель затем отправляет содержимое файла. Затем получатель будет повторно считывать 1024-байтовые куски из входного потока сокета, вставляя байты в img_data. Если ожидаемых байтов больше нет (или сокет закрыт), получатель отправит «ОК» отправителю (безусловно) и завершит работу. Отправитель просто распечатает это «ОК» (в байтах) и выйдет.

Часть этого можно исправить с помощью ByteArrayOutputStream, но я хотел максимально приблизиться к функциональности вашего кода.

0 голосов
/ 30 июня 2018

Что-то не так - вы должны получить какую-то ошибку при попытке отправить целое число в сокет:

>>> import socket
>>> s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
>>> s.connect(('localhost', 7777))
>>> s.sendall(len(b'some bytes'))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: a bytes-like object is required, not 'int'

Сокеты могут отправлять только bytes, вам нужно каким-то образом преобразовать объект int, содержащий размер, в bytes, python не сделает это автоматически за вас. Ваш код должен завершиться с ошибкой выше.

В коде Java, который вы используете asIntBuffer() и Integer.toBinaryString для преобразования ваших значений, в коде Python, который вы просто пытаетесь отправить данные без преобразования, вы должны получить ошибку.

Теперь, чтобы преобразовать int в bytes, вы можете использовать модуль struct; Он преобразуется в двоичное представление, используемое языком C - я думаю, именно этого ожидает ваш код Java

 size_in_bytes = struct.pack('I', len(data_to_send))

Таким же образом вы должны использовать struct.unpack для преобразования байтов обратно в целочисленный объект. См. документацию для получения более подробной информации и таблицы возможных преобразований.

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