Некоторые вопросы о java Datagram Socket

Недавно я погрузился в программирование сокетов с использованием java, и у меня есть несколько общих вопросов.

Существует метод bind(), а также connect() и разъединение(). Развязки () нет. Это потому, что при отключении сокет не привязан? Заботится ли сборка мусора об этом после выхода из программы? Или это даже не корректный вопрос?

Кроме того, при создании DatagramSocket, чем отличается, если я укажу только порт и адрес? Я создаю программу для сбора данных из сети, поскольку данные плавают вокруг и регистрируют их. Должен ли я просто использовать локальный адрес? Не может ли использование адреса при создании сокета привести к тому, что я не смогу собирать пакеты?

Я просто пытаюсь лучше понять внутреннюю работу этих вещей.


person Cat    schedule 15.06.2011    source источник
comment
Для начала может оказаться полезным Все о дейтаграммах.   -  person mre    schedule 15.06.2011
comment
Спасибо, я просмотрел это, но не совсем понял вышеизложенное.   -  person Cat    schedule 15.06.2011


Ответы (2)


Там около 15 независимых вопросов, но я сделаю все возможное, чтобы ответить на них:

Существует метод bind(), а также connect() и разъединение(). Развязки () нет. Это потому, что при отключении сокет не привязан?

bind() отделен от connect() и disconnect(). Bind используется для привязки сокета к определенному порту - эффективно «прослушивать» соединения, тогда как connect() используется для открытия соединения с сокетом, который уже прослушивает определенный порт. Эквивалентом unbind() является close()

Заботится ли сборка мусора об этом после выхода из программы? Или это даже не корректный вопрос?

Это абсолютно правильный вопрос, хотя сборка мусора — это технология, используемая для управления памятью, а не для управления ресурсами сокета/ОС. Если вы не освободите определенный порт, он останется связанным с вашим приложением до тех пор, пока ваше приложение не завершится, а затем он будет возвращен ОС. Это функциональность уровня ОС, а не функциональность JVM и т. д.

Кроме того, при создании DatagramSocket, чем отличается, если я укажу только порт или укажу порт и адрес?

В какой-то момент вы должны указать интернет-адрес и порт или сокет, к которому вы хотите подключиться или выполнить привязку. Нет никакого способа обойти это.

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

Я не уверен, что вы здесь спрашиваете, вы говорите о регистрации всех пакетов в сети, также известном как сниффер? Это потребует большего, чем простое программирование дейтаграмм. На самом деле вам нужно вводить себя на уровне сетевого адаптера, чтобы перехватывать пакеты, когда они считываются с линии. То, о чем вы говорите, позволит вам получать только те пакеты, которые отправляются на конкретный порт, который вы слушаете.

person Chris Thompson    schedule 15.06.2011
comment
Нет, не нюхач. Это просто программа для сбора пакетов с определенных портов, подключенных к устройствам мониторинга, таким как радар/GPS и т. д. Я просто пытаюсь собрать данные с этих конкретных портов. Это был скорее вопрос, должен ли я использовать адрес для объявления сокета, или я могу просто использовать этот порт? Насколько я понимаю, я просто возьму локальный адрес и буду использовать его. - person Cat; 15.06.2011
comment
Если вы не освободите определенный порт, он останется связанным с вашим приложением до тех пор, пока ваше приложение не завершится, а затем он будет возвращен ОС, если сокет был GC'd во время finalize(), он будет также закрыты. Также привязать () - person bestsss; 15.06.2011
comment
В какой-то момент вы должны указать интернет-адрес и порт или сокет, к которому вы хотите подключиться или выполнить привязку. Обойти это невозможно. Нет необходимости указывать порт для привязки, ОС выберет его за вас, если адрес не указан, используется INADDR_ANY (привязан к 0.0.0.0) - person willjcroz; 15.06.2011
comment
@Chris Можем ли мы написать сниффер (например, WireShark) с использованием Java? - person Pacerier; 16.07.2012
comment
Можно ли снова открыть закрытый сокет через bind()? - person Pacerier; 16.07.2012
comment
@Pacerier на ваш первый вопрос, да, технически. WireShark использует libpcap, которая является библиотекой C (вероятно, и C++). Вы можете подключиться к выходу или написать свой собственный интерфейс для libpcap. Я не верю, что закрытый сокет можно снова открыть, но я не уверен в этом на 100%. - person Chris Thompson; 16.07.2012
comment
@pacerier Закрытый сокет перестал существовать. Нет возможности заново открыть его. - person user207421; 01.05.2016

DatagramSocket остается связанным при отключении, это метод close(), который отвязывает его. Обратите внимание, что для сокета UDP (дейтаграммы) семантика connect() и disconnect() отличается от сокета TCP (или другого, ориентированного на соединение). UDP — это протокол без установления соединения, и связанный DatagramSocket может отправлять и получать пакеты без «подключения». Метод connect() имеет чисто локальный эффект, поскольку он позволяет сокету отправлять и получать пакеты только на заданный хост/порт, т. е. действует как фильтр. DatagramSocket, подключенный к многоадресному или широковещательному адресу, сможет только отправлять пакеты, но не получать их.

bind(SocketAddress) используется для присоединения сокета к комбинации локального адреса/порта, пока сокет не будет привязан, он не может получать или отправлять какие-либо пакеты. Поведение конструкторов по умолчанию заключается в немедленной привязке сокета. Чтобы создать несвязанный 'DatagramSocket', используйте конструктор DatagramSocket(SocketAddress), передающий null в качестве аргумента. Затем можно применить к сокету любую пользовательскую конфигурацию, прежде чем связывать его с bind().

Насколько я знаю, открытый DatagramSocket, выходящий за пределы области действия, вызовет утечку ресурсов, объект может быть собран мусором, но я почти уверен, что базовый сокет UDP останется выделенным ОС до тех пор, пока процесс JVM не завершится.

Если адрес не указан до привязки сокета, при привязке он будет присоединен к адресу с подстановочным знаком (INADDR_ANY), что позволяет ему получать и отправлять пакеты с любого доступного локального адреса (если только он позже не будет "подключен" к какому-либо хосту). Если порт не указан (или указан как 0), то сокет привязан к некоторому доступному порту, выбранному ОС (эфемерный порт).

Изменить: пример

// bind to INADDR_ANY, allowing packets on all IP addresses of host:
DatagramSocket dsock = new DatagramSocket(55555);
DatagramPacket packet = new DatagramPacket(new byte[8192]);

//next packet can be from anywhere including local host (127.0.0.0/8)
dsock.receive(packet);

// restrict communication to a single host/port:
dsock.connect(new InetSocketAddress("somehost.net", 99));

// next packet can only be from somehost.net on port 99:
dsock.receive(packet);
person willjcroz    schedule 15.06.2011
comment
Если я знаю, какой порт мне нужен, и я не достигаю многоадресной сети, необходимо указать адрес. Изменит ли это данные, которые я могу собирать? - person Cat; 15.06.2011
comment
Нет, нет никакой необходимости указывать адрес. Если вы не укажете адрес для привязки, ваш сокет будет эффективно «привязан» ко всем локальным адресам. Это будет означать, что ваш сокет может отправлять/получать пакеты в любых локальных сетях, к которым он подключен (и любые интернет-адреса, доступные через эти локальные сети), а также от любых локальных процессов в «петлевой» сети 127.0.0.0/8. полезно, если вы не знаете локальный IP-адрес вашего хоста, например он получает их через DHCP. - person willjcroz; 15.06.2011
comment
А, это имеет смысл. Спасибо - person Cat; 15.06.2011