Увеличьте скорость передачи TCP-сокета в java/android

Я разрабатываю приложение для прямой передачи файлов через Wi-Fi. Я вижу, что скорость передачи с использованием TCP-сокета неудовлетворительна. Скорость обычно 1 Мбит/с. Всякий раз, когда я анализирую график передачи данных, я вижу много пиков, и многие секунды вообще не передаются. Я знаю, что скорость передачи должна быть намного выше (может быть 20-30 Мбит/с). Пожалуйста, помогите мне увеличить скорость передачи. Серверный сокет, который принимает соединение,

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. Помоги мне

Обновление: см. следующий график передачи График скорости передачи


person Dipendra    schedule 17.04.2013    source источник
comment
Вам действительно нужно сбрасывать буфер так часто, что весь смысл буферизации состоит в том, чтобы уменьшить количество системных вызовов/сбросов?   -  person Peter Lawrey    schedule 17.04.2013
comment
Спасибо за комментарий. Я удалил эти флеши. Однако мне это не помогло, так как было всего 2-3 звонка.   -  person Dipendra    schedule 17.04.2013


Ответы (2)


Похоже, вы перегружаете буфер из setReceiveBufferSize() javadoc

Впоследствии можно изменить значение, вызвав Socket.setReceiveBufferSize(int). Однако, если приложение хочет разрешить окно приема размером более 64 КБ, как определено в RFC1323, то предлагаемое значение должно быть установлено в ServerSocket, прежде чем оно будет привязано к локальному адресу. Это означает, что ServerSocket должен быть создан с помощью конструктора без аргументов, затем должен быть вызван setReceiveBufferSize() и, наконец, ServerSocket привязан к адресу путем вызова bind().

person RuntimeError    schedule 17.04.2013
comment
Большое спасибо за точное определение. Я исправил свой код в соответствии с вашим предложением. Сейчас скорость 2-3 Мбит/с при TCP_BUFFER_SIZE=1024*1024. Но я считаю, что скорость все еще может быть намного выше. Ваша дальнейшая помощь будет высоко оценена. - person Dipendra; 17.04.2013

Я бы попробовал простую передачу данных с использованием простого сокета без использования файлов.

Иметь простой сервер, который отправляет 100 МБ пустых данных при подключении. Попросите клиента прочитать эти данные как можно быстрее, чтобы сообщить о полученной пропускной способности. На той же машине вы должны легко увидеть более 100 МБ/с. Как только это даст хорошее число, попробуйте его на клиенте Android.

person Peter Lawrey    schedule 17.04.2013