【问题标题】:How to allocate 20 MB for file received on socket in Android如何为 Android 中套接字上接收的文件分配 20 MB
【发布时间】:2017-08-11 03:43:42
【问题描述】:

我不断收到“内存不足”的问题。我看到了很多线程,并且我了解 Android 操作系统会限制主要内存块。但是这些文件共享应用程序是如何工作的呢?

我的代码在 10 MB 以下可以正常工作,但对于 10-15 MB 它有时可以工作,有时不能,对于 15 MB + 它永远不会工作。

我在这里尝试分配大约 11 MB,但有时也会失败。

我在 Manifest 中尝试了 android:largeHeap="true" 。没有帮助。

实际上,我必须转移一些已经压缩的视频。有什么建议吗?

我的代码 sn-p:

 public class FileTxThread extends Thread {
        private  ServerSocket serverSocket;
        private  Socket clientSocket;
        private InputStream inputStream;
        private FileOutputStream fileOutputStream;
        private BufferedOutputStream bufferedOutputStream;
        private  int filesize = 11728640; // filesize temporary hardcoded
        private  int bytesRead;
        private  int current = 0;
        Socket socket;

        FileTxThread(Socket socket){
            this.socket= socket;
            Log.d("naval", "constructor file thread initialized");
        }

        @Override
        public void run() {

            Log.d("lvmh", "Run function  file thread");
            byte[] mybytearray = new byte[filesize];    //create byte array to buffer the file
            try {
                inputStream = socket.getInputStream();


                // check for SD card mounted
                if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState()))
                {
                    Log.d("naval", "Mounted");
                }

                bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                Log.d("lvmh","Rceiving setting path"+imageCount);



                //System.out.println("Receiving...");


                //following lines read the input slide file byte by byte
                bytesRead = inputStream.read(mybytearray, 0, mybytearray.length);
                current = bytesRead;

                do {
                    bytesRead = inputStream.read(mybytearray, current, (mybytearray.length - current));
                    if (bytesRead >= 0) {
                        current += bytesRead;
                    }
                } while (bytesRead > -1);
                Log.d("lvmh", ">>>>>Receiving" + bytesRead);
                Log.d("lvmh",">>>>>navalllllllllll bytes read - "+current);
                bytesRead = 0; //reset


                try {
                    if(current>20)
                    {
                        fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory() + "/lvmh/"+imageCount+"img.mp4");
                        videoflag = true;
                        Log.d("lvmh","Mp4 received in bytes- "+current);
                    }
                    else{
                        fileOutputStream = new FileOutputStream(Environment.getExternalStorageDirectory() + "/lvmh/" +imageCount+"img.jpg");
                        Log.d("lvmh","Image received in bytes- "+current);
                    }

                }catch (IOException e)
                {
                    e.printStackTrace();
                }

                bufferedOutputStream = new BufferedOutputStream(fileOutputStream);
                Log.d("LVMH","Rceiving setting path"+imageCount);


                bufferedOutputStream.write(mybytearray, 0, current);

【问题讨论】:

  • “但是这些文件共享应用程序是如何工作的呢?” - 我希望他们读取一些字节,使用它们,读取更多字节(进入用于第一个字节的同一个缓冲区),使用它们等等。所以,在你的情况下,使用更像 16KB 的缓冲区,不是 10MB。“我必须转移一些已经压缩的视频”——“转移一些视频”是什么意思?
  • 移位意味着通过套接字传输。你是说我应该使用一个特定的缓冲区,比如 16 个字节并继续重写它?
  • 好吧,我会使用一个介于 16 字节和 11728640 字节之间的值。我建议 16KB,也就是 16384 字节。毕竟,您已经在 do... while 循环中“重新编写它”,因为您可能无法从套接字读取 11728640 字节。
  • 你能建议我应该改变哪个部分吗?我很困惑。
  • 我建议你把11728640换成16384。当然,我真正建议你摆脱所有这些并使用一些更高级别的网络代码,处理 SSL 和其他安全方面的东西。

标签: android sockets file-transfer


【解决方案1】:

socket.setReceiveBufferSize(11728640); //11.72864 MB -- 这就是为什么有时你会在 10-15 MB 上失败

因为,这里不需要知道impl,你只需拨打socket.setReceiveBufferSize(11728640);,它就会解决你的问题。 impl 是 LocalSocketImpl 类 (link) 的一个实例。但是,如果您想了解更多,setReceiveBufferSize() 的实现如下:

public void setReceiveBufferSize(int size) throws IOException 
    {
        impl.setOption(SocketOptions.SO_RCVBUF, Integer.valueOf(size));
    }

了解更多:https://alvinalexander.com/java/jwarehouse/android/core/java/android/net/LocalSocket.java.shtml

当您调用setReceiveBufferSize() 时,内核在使用setsockopt(2) 设置该值时将该值加倍(以便为簿记开销留出空间),并且该加倍值由getsockopt(2) 返回。见链接:http://man7.org/linux/man-pages/man7/socket.7.html

现在,您的套接字有 11728640 KB 的双倍大小的缓冲区。您不应该遇到“内存不足”的问题。

请注意堆空间socket无关。 SocketBuffer有关。

默认大小为 4K。您可以在此处找到此信息。 https://developer.android.com/reference/java/net/SocketOptions.html#SO_RCVBUF

SO_RCVBUF 常量用于提示操作系统相应地更改 ReceiveBuffer 大小。

【讨论】:

  • 所以我必须调用 setReceiveBufferSize () 字节数组分配?什么是 impl.setOption?
  • @NavalJoshi,alvinalexander.com/java/jwarehouse/android/core/java/android/…。我也会非常适当地更新我的答案。
  • 你是对的。需要告知套接字预期的缓冲区大小。 socket.setReceiveBufferSize(10728640);字节[] mybytearray = 新字节[文件大小];为我工作。
  • @NavalJoshi,我也在实现它。我会加强我的回答。很高兴,它解决了你的问题。
猜你喜欢
  • 1970-01-01
  • 2023-03-30
  • 2014-07-31
  • 2021-12-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-05
  • 1970-01-01
相关资源
最近更新 更多