powered by simpleCommunicator - 2.0.61     © 2026 Programmizd 02
Целевая тема:
Создать новую тему:
Автор:
Закрыть
Цитировать
Форумы / Java [игнор отключен] [закрыт для гостей] / Загадка про сокеты и NIO.
22 сообщений из 22, страница 1 из 1
Загадка про сокеты и NIO.
    #38472480
Dymytry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
День добрый!

Играюсь с сокетами и NIO. Написал следующее: NIO клиент соединяется с NIO сервером и последний начинает слать на клиента данные. Однако скорость отсылки сервером БОЛЬШЕ скорости считывания клиентом: к примеру сервер шлет 1000 байт, а потом спит секунду, а клиент читает 1000 байт, а потом спит 3 секунды. Рано или поздно сервер перестает слать данные непрерывно и начинает жда пока клиент их считает. Засекаю сколько байт было отослано и сколько считано. Между этими двумя цифрами ЕСТЬ РАЗНИЦА.

На моем компе эта разница всегда около 28000 байт. Вопрос: где эта разница хранится?

Логично предположить, что в буферах сокетов. Однако getSendBufferSize() на сервере и getReceiveBufferSize() на клиенте выдают по 8192. До 28000 не хватает.

Замечу также, что если написать аналогичный setup на простых сокетах, то все будет точно так же, однако разница будет составлять всегда 8000 байт, что хотя бы соответствует размеру getReceiveBufferSize() клиента, а точно такой же размер getSendBufferSize() получается не учитывается.

Поясните магию, пожалуйста.

ps
Windows, клиент и сервер на одной машине, соединение через 127.0.0.1.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473155
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dymytry,

скорей всего, облажались с подсчетом байтиков, и разницы нет. Хотя без кода так никто вам не скажет точно.

еще лучше распечатать сколько отправлено и сколько принято на каждой итерации, тогда можно что-то понять.
поток можно "мерять" сниффером типа wireshark, у него там есть follow tcp stream, где можно посмотреть сырые данные, которые бегают.

только под виндой wireshark не увидит трафик через 127.0.0.1. Ставье линукс или гоняйте данные по сети.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473303
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
DymytryЛогично предположить, что в буферах сокетовНифига не логично.
Над IP-стеком есть JVM со своими представлениями о прекрасном. Имеет полное право копить данные до считывания приложением, предоставив IP-стеку место для их размещения.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473425
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dymytry

Я вспоминаю жлобские времена интернетов с помегабайтной оплатой. Провайдеры
считали трафик по разным формулам. Кто-то учитывал входящий. Кто-то входящий
и исходящий вместе. Кто-то в совокупности с IPCMP-пакетами или IP. Но это
лирика...

Дело в том что "байты" не являются единицей учёта трафика в сетях. Там оперируют
более крупными вагончиками и тележками.

Что ты считал и "засекал" - непонятно. По хорошему ты должен был воспользоваться
сетевыми утилитами iptraf или tcpdump. Они выдают реальную картину происходящего.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473619
Dymytry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Вот мой пионерский код. Вроде все линейно, но может я где-то не прав?..

Клиент, который читает раз в секунду:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
public class NioClient {
    public static void main(String[] args) throws InterruptedException {
        try {
            SocketAddress address = new InetSocketAddress("127.0.0.1", 80);
            SocketChannel client = SocketChannel.open(address);
            ByteBuffer buffer = ByteBuffer.allocate(1000);
            int read = 0;
            client.configureBlocking(false);
            buffer.rewind();
            Thread.sleep(500); //without this server do not have time to write something to client
            int totalRead = 0;
            while ((read = client.read(buffer)) > 0) {
                totalRead += read;
                System.out.println("has read " + totalRead);
                buffer.rewind();
                Thread.sleep(1000);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}



Сервер, который пишет без задержек:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
public class NioServer {
    public static void main(String[] args) throws IOException, InterruptedException {
        int size = 1000;
        byte[] data = new byte[size];
        for (int i = 0; i < size; i++) {
            data[i] = (byte) i;
        }
        ByteBuffer buffer = ByteBuffer.allocate(size);
        ServerSocketChannel serverChannel;
        Selector selector;
        int totalWritten = 0;
        try {
            serverChannel = ServerSocketChannel.open();
            ServerSocket ss = serverChannel.socket();
            InetSocketAddress address = new InetSocketAddress(80);
            ss.bind(address);
            serverChannel.configureBlocking(false);
            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException ex) {
            ex.printStackTrace();
            return;
        }
        while (true) {
            try {
                selector.select();
            } catch (IOException ex) {
                ex.printStackTrace();
                break;
            }
            Set readyKeys = selector.selectedKeys();
            Iterator iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector, SelectionKey.OP_WRITE);
                        totalWritten = 0;
                    } else if (key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        int res = client.write(buffer);
                        totalWritten += res;
                        System.out.println(totalWritten + " bytes written.");
                        buffer.rewind();
                    }
                } catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException cex) {
                    }
                }
            }
        }
    }
}



Output:
автор286000 bytes written.
287000 bytes written.
288000 bytes written.
289000 bytes written.
290000 bytes written.
291000 bytes written.
...
has read 253000
has read 254000
has read 255000
has read 256000
has read 257000
has read 258000
has read 259000
has read 260000
has read 261000
has read 262000


Вопрос в том где хранится разница.

Базиль, то есть оно может хранится в JVM? А как это понять, что посмотреть, потрогать, почитать?
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473627
Dymytry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
(случайно стер вместе c комментами строчку buffer.put(data), но она есть :), а редактировать посты тут нельзя что ли.. )
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473642
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dymytry(случайно стер вместе c комментами строчку buffer.put(data), но она есть :), а редактировать посты тут нельзя что ли.. )
Выкладывай правильный сорс еще раз. И импорты добавь. Не ленись.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38473809
Dymytry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Ну ок, вот еще раз сервер целиком:

Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class NioServer {

    public static void main(String[] args) throws IOException, InterruptedException {
        int size = 1000;
        byte[] data = new byte[size];
        for (int i = 0; i < size; i++) {
            data[i] = (byte) i;
        }
        ByteBuffer buffer = ByteBuffer.allocate(size);
        buffer.put(data);
        ServerSocketChannel serverChannel;
        Selector selector;
        int totalWritten = 0;
        try {
            serverChannel = ServerSocketChannel.open();
            ServerSocket ss = serverChannel.socket();
            InetSocketAddress address = new InetSocketAddress(80);
            ss.bind(address);
            serverChannel.configureBlocking(false);
            selector = Selector.open();
            serverChannel.register(selector, SelectionKey.OP_ACCEPT);
        } catch (IOException ex) {
            ex.printStackTrace();
            return;
        }
        while (true) {
            try {
                selector.select();
            } catch (IOException ex) {
                ex.printStackTrace();
                break;
            }
            Set readyKeys = selector.selectedKeys();
            Iterator iterator = readyKeys.iterator();
            while (iterator.hasNext()) {
                SelectionKey key = (SelectionKey) iterator.next();
                iterator.remove();
                try {
                    if (key.isAcceptable()) {
                        ServerSocketChannel server = (ServerSocketChannel) key.channel();
                        SocketChannel client = server.accept();
                        client.configureBlocking(false);
                        client.register(selector, SelectionKey.OP_WRITE);
                        totalWritten = 0;
                    } else if (key.isWritable()) {
                        SocketChannel client = (SocketChannel) key.channel();
                        int res = client.write(buffer);
                        totalWritten += res;
                        System.out.println(totalWritten + " bytes written.");
                        buffer.rewind();
                    }
                } catch (IOException ex) {
                    key.cancel();
                    try {
                        key.channel().close();
                    } catch (IOException cex) {
                    }
                }
            }
        }
    }
}



Клиент:
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
package nio;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;

public class NioClient {
    public static void main(String[] args) throws InterruptedException {
        try {
            SocketAddress address = new InetSocketAddress("127.0.0.1", 80);
            SocketChannel client = SocketChannel.open(address);
            ByteBuffer buffer = ByteBuffer.allocate(1000);
            int read = 0;
            client.configureBlocking(false);
            buffer.rewind();
            Thread.sleep(500); //without this server do not have time to write something to client
            int totalRead = 0;
            while ((read = client.read(buffer)) > 0) {
                totalRead += read;
                System.out.println("has read " + totalRead);
                buffer.rewind();
                Thread.sleep(1000);
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
}
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38474958
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
а где тут распечатываются размеры буферов приема-отправки?

сделайте так:
System.out.println("rcv size ="+ client.getOption(StandardSocketOptions.SO_RCVBUF) );
System.out.println("snd size ="+ client.getOption(StandardSocketOptions.SO_SNDBUF) );

на клиенте распечатайте прием, на сервере - отправку. И когда будут известны эти величины, уже дальше будем думать.

на моем компе сервер пишет
snd size =331875
при этом за раз при подключении в сокет улетает 1018000

при этом клиент пишет rcv size =131003

Действительно, есть разница. При этом cat /proc/sys/net/ipv4/tcp_wmem выдает
4096 16384 4194304

Получается, что над внутреним буфером сетевухи есть буфер ОС, над которым, насколько понимаю, буфер жабы. Получается, что так.
Получается, что у неблокирующих сокетов нету zero-copy политики. Да, действительно печально. Чтобы отправить данные, их надо сначала положить в ByteBuffer, откуда они копируются в буфер ОС, откуда они уходят в буфер сетевой карты.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38475047
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
У меня
Код: java
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
rcv size = 8192
snd size = 8192
Java version  = 1.7.0_13
OS Name    = Windows 7
OS Version = 6.1
has read 1000
has read 2000
has read 3000
has read 4000
has read 5000
has read 6000
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38475052
Adva
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Гость
Посмотри исходные коды Netty. В презентации http://www.slideshare.net/danbim/zerocopy-eventdriven-servers-with-netty уверяют что один ByteBuffer из описанной выше цепочки - лишний.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38475193
Dymytry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapok ,
у меня 6я Джава и такого метода еще нет, использую client.socket().getSendBufferSize(), который внутри есть Object o = getImpl().getOption(SocketOptions.SO_SNDBUF), думаю это одно и то же. Буферы равны 8192 на прием и на отсылку, а таинственная разница между отправленным и принятым - в районе 27000, Windows 7.

Не знаю, есть ли какой-то буфер в самой JVM. Но есть буфер сокета и буфер сетевой карты. Может, помимо буфера сокета есть еще какой-то буфер от ОС. Может, данная разница таится в буфере сетевой карты. Не знаю как его узнать. Вообще непонятно где копать инфу по таким задачкам "на стыке". Книжку бы какую кто посоветовал.

mayton ,
так разница между отправленным и полученным такая же должна быть - в 27000?

Adva ,
спасибо за наводку! правда у меня вряд ли тут случай zero-copy, потому что я не считываю ничего с диска, и мои данные в любом случае идут из Application (это просто массив который я создаю кодом). Но тема интересная, ага.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38476030
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dymytry,

По сетевым инфу ищут так - гуглят марку сетевой, или то что написано на микросхеме сетевухи. У вас 6 жаба? Некрожабер. У меня убунту, тоже как видите есть разница. Так что все ок, вроде бы. Это особенность протокола - при заполнении буферов tcp отвечает нулевым размером окна и передающая сторона приостанавливает передачу, поэтому нельзя надеяться, что будет иначе.

В противовес такой организации существует такая штука как "пить из пожарного крана". Когда передающая сторона просто шлет данные, а если прием не успевает - это его проблемы.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38476095
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Adva,

ясно что лишний
Я посмотрел исходники netty, в нем нету либ нативных. Значит, у него сокеты из nio, и его сокеты - надстройка над nio.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38476097
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Хм... И на coderanch успел вопрос задать.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38476921
Dymytry
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapok,
а вы уверены что сетевая карта вообще учавствует в этом процессе? это же Loopback. мне кажется, нет.
короче, где-то есть какие-то буферы :)

mayton,
я и на stackoverflow спросил, мне не жалко. однако ж подробнооо ответа никто не знает. нужно читать про устройство JVM, наверное, не знаю что именно. а coderanch слабоватый форум. интересно, какой форум по Джаве самый сильный?
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38476975
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokПолучается, что у неблокирующих сокетов нету zero-copy политикиНифига не получается.
Читал, в своё время, документацию по 4.1 версии IP-стека OS/2. Один из разделов объяснял, как предоставить ядру буферы пользовательского кода. Как раз для исключения копирования.
В Java, где пользовательский код вообще не может управлять механизмом выделения памяти, страдать об отсутствии zero-copy, как минимум, странно. При наличии Byte- и DirectBuffer - странно вдвойне.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38476994
Фотография mayton
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Dymytrymayton,
я и на stackoverflow спросил, мне не жалко. однако ж подробнооо ответа никто не знает. нужно читать про устройство JVM, наверное, не знаю что именно. а coderanch слабоватый форум. интересно, какой форум по Джаве самый сильный?
Откуда ты брал код Sever ? Сам написал или скопипастил?
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38477103
Фотография schwa
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
ubuntu 12.04
Ставлю в представленном выше коде различные значения SO_RCVBUF и количество отправленных сервером данных меняется в соответстующую сторону. Вполне закономерный результат.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38477229
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Basil A. Sidorov,

ну, и lwip тот же умеет. Но только как это все соотносится с java?

Так direct-буфер, если бы был таким уж прямым, то разницы про которую пишет тс не было б. Делаешь write - данные или сразу уходят в буфер сетевой, или возвращается 0. А разница есть. Или я что-то плохо понимаю.

Вечером попробую чесную пересылку, между двумя компами, без всяких там loopback-ов. Действительно, этот loopback не пойми как работает, может быть дело в нем.
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38480453
Basil A. Sidorov
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
chabapokНо только как это все соотносится с java?Есть буфер и лежащий в его основе машинный указатель.
Машинный указатель не доступен на уровне прикладного кода, но, в любом случае, есть два способа поместить в буфер новые данные:
1. Скопировать данные, не изменяя машинный указатель;
2. Изменить машинный указатель, не копируя данные.
Способы можно комбинировать.
Вы готовы положить член на отруб, что точно знаете, как именно работает JVM+библиотека классов+нативные методы?
...
Рейтинг: 0 / 0
Загадка про сокеты и NIO.
    #38480493
chabapok
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Участник
Не готов даже там, где знаю точно о особенностях реализации. Так что готов или не готов - это не показатель, и в таком ключе рассуждать нельзя.
...
Рейтинг: 0 / 0
22 сообщений из 22, страница 1 из 1
Форумы / Java [игнор отключен] [закрыт для гостей] / Загадка про сокеты и NIO.
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]