【问题标题】:Sending a photo from a device using Python3 and receiving it on an Android Device via TCP gives an OOM on the Android Device使用 Python3 从设备发送照片并通过 TCP 在 Android 设备上接收照片会在 Android 设备上产生 OOM
【发布时间】:2019-05-03 12:42:00
【问题描述】:

我正在尝试使用 Python 3 从我的 Raspberry Pi 将照片发送到我的 Android 设备。我通过 TCP 执行此操作,Pi 作为客户端,Android 设备作为我的服务器。我的目标是将照片文件从 Pi 发送到我的 Android 设备。然后,我的 Android 设备将解码该照片数据,然后将其设置为我的应用程序中 ImageView 的可绘制对象。请注意,我发送的是 640x480 的 200kB 图像。

我尝试了一种设置,让 Pi 通过 TCP 将文本发送到我的 Android 设备,我已经成功了。

接下来我尝试将照片从 Python3 客户端发送到 Python3 服务器。在这种情况下,我仍然使用 Pi 作为我的客户端,我使用我的 MacOS 笔记本电脑作为服务器。这是我最终使用的代码。

服务器 - MAC 操作系统

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 笔记本电脑。

现在,我使用the code here as reference 将我的照片从我的 Pi 传输到我的 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

我有一种预感,在第二个错误中,我试图用一个实际上已经是图像数据的值初始化字节数组,因此出现 OOM 错误。

但是,如果我只取第一个值并将其分配为 len,我有可能得到一个负数,并且代码会遇到第一个错误。

是否有可能我必须进行一些调整才能将照片数据从 Python3 传输到 Android?我感觉正在发生某种格式不匹配的情况。

同样,我的目标是通过 TCP 从 Python3 将照片文件发送到我的 Android 设备。 Python3 将获得一个文件,Android 设备将对它获得的输入进行解码,解码后,将该数据用作 ImageView 的可绘制对象。

【问题讨论】:

    标签: android python-3.x sockets tcp file-transfer


    【解决方案1】:

    据我说,错误是由您尝试为ImageView 设置的位图大小引起的。在使用前检查大小和/或缩放位图可能会解决问题。在我开始使用第三方库加载图像之前,我过去曾遇到过此类问题。

    你可以看看这篇来自 Android Developers 的文章,我认为它会有所帮助:

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

    【讨论】:

    • 我的文件只有 196KB,是 640x480 的图像。
    【解决方案2】:

    我明白了。你应该使用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();
    

    【讨论】:

      猜你喜欢
      • 2012-04-10
      • 2010-12-10
      • 2018-12-20
      • 1970-01-01
      • 2014-05-31
      • 1970-01-01
      • 2023-03-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多