Увеличете скоростта на трансфер на TCP сокет в java /android

Разработвам приложение за прехвърляне на файлове, базирано на wifi direct. Виждам, че скоростта на трансфер чрез TCP сокет не е задоволителна. Скоростта обикновено е 1Mbps. Всеки път, когато анализирам графиката за пренос на данни, виждам много скокове и много секунди са без прехвърляне на данни. Знам, че скоростта на трансфер трябва да е много по-висока (може да е 20-30Mbps). Моля, помогнете ми да увелича скоростта на трансфер. Сървърният гнездо, което приема връзката, е

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). Въпреки това, ако приложението желае да позволи прозорец за получаване, по-голям от 64K байта, както е дефинирано от RFC1323, тогава предложената стойност трябва да бъде зададена в ServerSocket, преди да бъде обвързана с локален адрес. Това означава, че ServerSocket трябва да бъде създаден с конструктор без аргументи, след което трябва да се извика setReceiveBufferSize() и накрая ServerSocket се свързва с адрес чрез извикване на bind().

person RuntimeError    schedule 17.04.2013
comment
Благодаря ви много за точното определяне. Коригирах кода си според вашето предложение. Сега скоростта е 2-3 Mbps с TCP_BUFFER_SIZE=1024*1024. Но вярвам, че скоростта все още може да бъде много по-бърза. По-нататъшната ви помощ ще бъде високо оценена. - person Dipendra; 17.04.2013

Бих опитал просто прехвърляне на данни с помощта на обикновен Socket без използване на файлове.

Имате прост сървър, който изпраща 100 MB празни данни, когато се свържете. Накарайте клиента да прочете тези данни възможно най-бързо, за да отчете получената пропускателна способност. На същата машина трябва лесно да видите над 100 MB/s. След като това даде добър номер, опитайте го на Android клиент.

person Peter Lawrey    schedule 17.04.2013