Отправка фотографии с устройства с помощью Python3 и получение ее на устройстве Android через TCP дает OOM на устройстве Android - PullRequest
0 голосов
/ 01 декабря 2018

Я пытаюсь отправить фотографию с моего Raspberry Pi с помощью Python 3 на мое Android-устройство.Я делаю это через TCP с Pi в качестве клиента и Android-устройством в качестве моего сервера.Моя цель - отправить файл фотографии с Pi на мое Android-устройство.Мое Android-устройство затем декодировало бы эти данные фотографий, а затем установило их в качестве рисунка для ImageView в моем приложении.Пожалуйста, обратите внимание, что я отправляю изображение размером 200 КБ с разрешением 640x480.

Я пробовал установить, где Pi отправляет текст на мое Android-устройство через TCP, и у меня это получилось.

Далее я попытался отправить фотографию с клиента Python3 на сервер Python3.В этом случае я все еще использовал Pi в качестве своего клиента, а ноутбук MacOS использовал в качестве сервера.Это код, который я в конечном итоге использовал.

Сервер - MAC OS

import socket               # Import socket module

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
port = 11111                 # Reserve a port for your service.
s.bind((host, port))        # Bind to the port
f = open('torecv.jpg','wb')
s.listen(5)                 # Now wait for client connection.
while True:
    c, addr = s.accept()     # Establish connection with client.
    print('Got connection from', addr)
    print("Receiving...")
    l = c.recv(1024)
    while (l):
        print("Receiving...")
        f.write(l)
        l = c.recv(1024)
    f.close()
    print("Done Receiving")
    c.send(b'Thank you for connecting')
    c.shutdown(socket.SHUT_RDWR)
    c.close()                # Close the connection

Клиент - Pi

import socket               # Import socket module
import os

s = socket.socket()         # Create a socket object
host = socket.gethostname() # Get local machine name
host = '192.168.254.194' # Get local machine name

port = 6001                 # Reserve a port for your service.

CWD_PATH = os.getcwd()
PATH_TO_IMG_DIR = os.path.join(CWD_PATH, 'img_folder', 'test.jpg')

s.connect((host, port))


#s.send(b'Hello Server!')
f = open(PATH_TO_IMG_DIR,'rb')

print('Sending...')
l = f.read(1024)
while (l):
    print('Sending...')
    s.send(l)
    l = f.read(1024)
f.close()
print("Done Sending")
s.shutdown(socket.SHUT_WR)
print(s.recv(1024))
s.close                     # Close the socket when done

Используя этот код, я смог перенести фотографию с моего Pi на мой ноутбук MacOS.

Теперь я использовал код здесь как ссылку , чтобы перенести мою фотографию с моего Pi на мое Android-устройство.Вот мой код:

Сервер - Android

class ServerThread implements Runnable {

    public void run() {
        Socket socket;
        try {
            Log.e(TAG, "starting the serverthread at port 6001");
            serverSocket = new ServerSocket(6001);
        } catch (IOException e) {
            Log.e(TAG, "exception in creating server socket: ", e);
            e.printStackTrace();
        }
        while (!Thread.currentThread().isInterrupted()) {

            try {
                socket = serverSocket.accept();

                CommunicationThread commThread = new CommunicationThread(socket);
                new Thread(commThread).start();

            } catch (IOException e) {
            }
        }
    }
}


class CommunicationThread implements Runnable{
    private Socket clientSocket;

    private DataInputStream input;//private BufferedReader input;

    public CommunicationThread(Socket clientSocket) {

        this.clientSocket = clientSocket;

        try {
            Log.e(TAG, "getting data from the input stream!");
            //this.input = new BufferedReader(new InputStreamReader(this.clientSocket.getInputStream()));
            InputStream in = this.clientSocket.getInputStream();
            this.input = new DataInputStream(in);

        } catch (IOException e) {
            Log.e(TAG, "error in creating data input stream: ", e);
            e.printStackTrace();
        }
    }

    public void run() {
        Log.e(TAG, "running the code!");
        while (!Thread.currentThread().isInterrupted()) {
            try {
                Log.e(TAG, "parsing the input data stream!");
                byte[] data;//String read = input.readLine();
                int len= this.input.readInt();

                if (len > 0) {
                    data = new byte[len];
                    this.input.readFully(data,0,data.length);
                }
                    /*
                    ByteArrayOutputStream out = new ByteArrayOutputStream();
                    byte[] data;
                    int length = 0;
                    while ((length = this.input.read(data))!=-1) {
                        out.write(data,0,length);
                    }
                       data=out.toByteArray();
                    */

                Log.e(TAG, "Updating the UI through a thread!!");

//              updateConversationHandler.post(new updateUIThread(data));
            } catch (IOException e) {
                // TODO Auto-generated catch block
                Log.e(TAG, "error in reading sent data! ", e);
                e.printStackTrace();
            }
        }
    }
}

И чтобы использовать эти классы, я объявил следующее как глобальные переменные:

Thread serverThread = null;
Handler updateConversationHandler;

И в моем onCreate() у меня есть следующее:

    updateConversationHandler = new Handler();

    this.serverThread = new Thread(new ServerThread());
    this.serverThread.start();

Приложение запустится, и сокет будет открыт.Однако, когда я пытаюсь отправить фотографию с моего Pi, я получаю сообщение об ошибке в этом блоке кода:

public void run() {
    Log.e(TAG, "running the code!");
    while (!Thread.currentThread().isInterrupted()) {
        try {
            Log.e(TAG, "parsing the input data stream!");
            byte[] data;//String read = input.readLine();
            int len= this.input.readInt();

            if (len > 0) {
                data = new byte[len];
                this.input.readFully(data,0,data.length);
            }
                /*
                ByteArrayOutputStream out = new ByteArrayOutputStream();
                byte[] data;
                int length = 0;
                while ((length = this.input.read(data))!=-1) {
                    out.write(data,0,length);
                }
                   data=out.toByteArray();
                */

            Log.e(TAG, "Updating the UI through a thread!!");

//          updateConversationHandler.post(new updateUIThread(data));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            Log.e(TAG, "error in reading sent data! ", e);
            e.printStackTrace();
        }
    }
}

class updateUIThread implements Runnable {
    private byte[] byteArray;//private String msg;

    public updateUIThread(byte[] array){    //public updateUIThread(String str) {
        this.byteArray=array;   //this.msg = str;
    }

    @Override
    public void run() {
        Log.e(TAG, "running the photo update!");
        Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray , 0, byteArray .length);
        ivBed.setImageBitmap(bitmap);//text.setText(text.getText().toString()+"Client Says: "+ msg + "\n");
    }
}

Первоначально строка:

data = new byte[len];

была внеif(len>0) состояние.Но по какой-то причине Pi отправил отрицательное значение, и, конечно, мы не хотим, чтобы отрицательное значение для переменной len.Конечно, я столкнулся с ошибкой при попытке создать байтовый массив data с отрицательной длиной.Затем я помещаю эту строку в условие if.

Однако после того, как я это сделал, я нажал OOM Error в той же строке data = new byte[len];

Process: agict.work.freelance.patientsensor, PID: 15224
java.lang.OutOfMemoryError: Failed to allocate a 1677608328 byte allocation with 6291456 free bytes and 254MB until OOM, max allowed footprint 7797480, growth limit 268435456

У меня есть догадка, что во 2-й ошибке я пытался инициализировать байтмассив со значением, которое на самом деле уже было данными изображения, следовательно, ошибка OOM.

Однако, если я просто возьму первое значение и назначу его как len, есть вероятность, что яполучить отрицательное число, и код попадет в первую ошибку.

Есть ли шанс, что мне придется что-то подправить, чтобы перенести фотографии с Python3 на Android?У меня такое чувство, что происходит несовпадение форматов.

Опять же, моя цель - отправить файл фотографии из Python3 на мое Android-устройство через TCP.Python3 получит файл, а Android-устройство будет декодировать входные данные, которые он получает, и после декодирования использовать эти данные в качестве объекта для ImageView.

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Я понял.Вы должны использовать ByteArrayOutputStream Объект.

class ServerImageThread implements Runnable{
    ServerSocket ss;
    Socket s;
    DataInputStream dis;

    byte[] data;

    @Override
    public void run(){
        try{
            ss = new ServerSocket(6001);

            while(true){
                s = ss.accept();
                InputStream in = s.getInputStream();
                dis = new DataInputStream(in);

                // read from the stream
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] content = new byte[1024];

                int bytesRead = -1;

                while( (bytesRead = in.read(content)) != -1 ) {
                    baos.write( content, 0, bytesRead );
                } // while

                Log.e(TAG, "made it through!");
                Log.e(TAG, "baos size is = " + baos.size());


                File file = new File(
                Environment.getExternalStorageDirectory(), "test.jpg");

                FileOutputStream fos = null;
                try {
                    fos = new FileOutputStream(file);
                    baos.writeTo(fos);

                    Log.e(TAG, "managed to write baos to fos");

                } catch(IOException ioe) {
                    // Handle exception here
                    Log.e(TAG, "baos IOException = ", ioe);
                    ioe.printStackTrace();
                } finally {
                    Log.e(TAG, "closing fos");
                    fos.close();
                } 
            }
        }
        catch(IOException e) {
            Log.e(TAG, "exception in creating server socket: ", e);
            e.printStackTrace();
        }
    }
}

Вы можете вызвать это через:

    Thread myThread = new Thread(new ServerImageThread());
    myThread.start();
0 голосов
/ 01 декабря 2018

По моему мнению, ошибка вызвана размером растрового изображения, которое вы пытаетесь установить для ImageView.Проверка размеров перед использованием и / или масштабирование растрового изображения может решить проблему.Я сталкивался с такими проблемами в прошлом, прежде чем начать использовать сторонние библиотеки для загрузки изображений.

Вы можете взглянуть на эту статью от разработчиков Android, и я думаю, что она может помочь:

https://developer.android.com/topic/performance/graphics/load-bitmap#java

...