在 java /android 中提高 TCP 套接字的传输速度

Posted

技术标签:

【中文标题】在 java /android 中提高 TCP 套接字的传输速度【英文标题】:Increase transfer speed of TCP socket in java /android 【发布时间】:2013-04-17 11:48:36 【问题描述】:

我正在开发基于 wifi direct 的文件传输应用程序。我可以看到使用 TCP 套接字的传输速度并不令人满意。速度通常为 1Mbps。每当我分析数据传输图时,我可以看到很多尖峰,而且很多秒根本没有数据传输。我知道传输速度应该更高(可能是 20-30Mbps) 请帮助我提高传输速度。 接受连接的serversocket是

private void serverTask() 
        Log.v(TAG, "server task");
        try 
            serverRunning = true;
            ServerSocket serverSocket = new ServerSocket(
                    DeviceDetailFragment.PORT);
            serverSocket.setReceiveBufferSize(TCP_BUFFER_SIZE);


            Socket client = serverSocket.accept();

            BufferedInputStream inputstream = new BufferedInputStream(
                    client.getInputStream());
            // new BufferedInputStream(client.getInputStream(), 8 * 1024);
            BufferedReader bufferedStream = new BufferedReader(
                    new InputStreamReader(inputstream));


                fileName = bufferedStream.readLine();
                fileSizeInBytes = bufferedStream.readLine();
                fileMime = bufferedStream.readLine();

                f = new File(Globals.fileSavingLocation + fileName);

                File dirs = new File(f.getParent());
                if (!dirs.exists())
                    dirs.mkdirs();

                if (f.exists()) 
                    f.delete();
                

                f.createNewFile();

        IOUtils.copy(inputstream, new FileOutputStream(f));


                serverSocket.close();
            
            isSuccessful = true;

         catch (IOException e) 
            isSuccessful = false;
            Log.e(TAG, e.getMessage());

        
        serverRunning = false;

    

发送数据的客户端有如下代码:

 private void clientTask(Intent intent) 
            String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
            String host = intent.getExtras().getString(EXTRAS_ADDRESS);
            String fileName = intent.getExtras().getString(FILE_NAME);
            String fileMimeType = intent.getExtras().getString(FILE_MIME_TYPE);
            final long sizeInBytes = intent.getExtras().getLong(FILE_SIZE);
            Socket socket = new Socket();
            int port = intent.getExtras().getInt(EXTRAS_PORT);

            try 
                socket.setSendBufferSize(TCP_BUFFER_SIZE);
                socket.bind(null);
                socket.connect((new InetSocketAddress(host, port)),
                        SOCKET_TIMEOUT);

                BufferedOutputStream stream = new BufferedOutputStream(
                        socket.getOutputStream());
                ContentResolver cr = FileTransferService.this
                        .getApplicationContext().getContentResolver();
                InputStream is = null;

                BufferedWriter bufferStream = new BufferedWriter(
                        new OutputStreamWriter(stream));


                bufferStream.write(fileName);
                bufferStream.newLine();
                bufferStream.flush();
                bufferStream.write(String.valueOf(sizeInBytes));
                bufferStream.newLine();
                bufferStream.flush();

                bufferStream.write(fileMimeType);
                bufferStream.newLine();
                bufferStream.flush();


                try 

                    is = new BufferedInputStream(cr.openInputStream(Uri
                            .parse(fileUri)));

                 catch (FileNotFoundException e) 

                    isSuccessful = false;

                
 IOUtils.copy(is, stream);


                isSuccessful = true;

             catch (IOException e) 
                Log.e(TAG, e.getMessage());
                isSuccessful = false;
             finally 
                if (socket != null) 
                    if (socket.isConnected()) 
                        try 
                            socket.close();
                         catch (IOException e) 
                            // Give up
                            e.printStackTrace();
                        
                    
                
            

TCP_BUFFER_SIZE 的值设置为1024*512

我尝试了很多改变 TCP_BUFFER_SIZE 的值,但没有成功。我用 Apache Commons IOUtils 替换了复制流的实现。 帮帮我

更新: 请看下面的传输图

【问题讨论】:

你真的需要如此频繁地刷新缓冲区吗,缓冲的全部意义在于减少系统调用/刷新的次数? 感谢您的评论。我已经删除了那些冲洗。但是,它并没有帮助我,因为它只是 2-3 个电话 【参考方案1】:

您似乎正在超载缓冲区,来自setReceiveBufferSize() javadoc

随后可以通过调用来更改该值 Socket.setReceiveBufferSize(int)。但是,如果应用程序希望 允许接收窗口大于 64K 字节,由 RFC1323 定义 那么建议的值必须先在 ServerSocket 中设置 绑定到本地地址。这意味着,ServerSocket 必须是 使用无参数构造函数创建,然后 setReceiveBufferSize() 必须调用,最后将 ServerSocket 绑定到一个地址 调用 bind()。

【讨论】:

非常感谢您的指点。我根据您的建议更正了我的代码。现在速度为 2-3 Mbps,TCP_BUFFER_SIZE=1024*1024。但我相信,速度还可以快得多。我们将非常感谢您的进一步帮助。【参考方案2】:

我会尝试使用普通 Socket 而不使用文件进行简单的数据传输。

有一个简单的服务器,在您连接时发送 100 MB 的空数据。让客户端尽可能快地读取该数据,并报告它获得的吞吐量。在同一台机器上,您应该很容易看到超过 100 MB/s 的速度。一旦这给出了一个好的数字,请在 android 客户端上尝试。

【讨论】:

以上是关于在 java /android 中提高 TCP 套接字的传输速度的主要内容,如果未能解决你的问题,请参考以下文章

java学习笔记之网络编程

Android调试注解处理器AnnotationProcessor

JAVA基础知识|Socket

Java-Wed 初认识

一起Talk Android吧(第三百一十九回:Android中网络通信之TCP概述)

Android之IPC(aidl)