Nano Hash - криптовалюты, майнинг, программирование

Java: как подключиться к разным серверам из клиентского сокета на один порт?

TCP-соединение идентифицируется четырьмя элементами (возможно, включая протокол): порт клиента, адрес клиента, порт сервера, адрес сервера. Таким образом, клиент с одним портом может подключаться к нескольким разным серверам. Потому что это разные TCP-соединения.

Вот моя демонстрация: локальный клиент на порту 9999 подключается к двум локальным серверам на портах 12345 и 12346. Но код неверен.

Кто-нибудь может мне помочь? Подскажите, пожалуйста, как это исправить (не использовать SO_REUSEPORT или форк)

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

public class SocketTest {

    public static void main(String[] args) throws IOException {


        startServer(12345);
        startServer(12346);

        Socket socket = new Socket();
        socket.bind(new InetSocketAddress(9999));
        System.out.println("client: " + socket.getLocalSocketAddress().toString());

        startClient(socket, 12345);
        startClient(socket, 12346);
    }

    public static void startClient(Socket socket, int port) {
        (new Thread() {
            @Override
            public void run() {
                try {
                    // Problem: connect() can be called only once
                    socket.connect(new InetSocketAddress(port));
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    public static void startServer(int port) {
        new Thread() {
            @Override
            public void run() {
                ServerSocket ss;
                try {
                    ss = new ServerSocket(port);
                    System.out.println("listen on: " + ss.getLocalSocketAddress());
                    while (true) {
                        Socket s = ss.accept();
                        System.out.println("accept from: " + s.getRemoteSocketAddress());
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }.start();
    }
}
17.08.2016

  • Почему? Какое вам дело, какой локальный порт использует клиент? «код неверный» — это не сообщение о проблеме. Почему SO_REUSEADDR неприемлем? Непонятно, что вы спрашиваете. 17.08.2016
  • Я просто хочу сделать демонстрацию, чтобы проверить свою мысль: можно подключиться к 2 разным серверам, используя сокет на одном порту. Однако мой код не работает так, как я хочу. Можете ли вы дать мне редакцию кода? 17.08.2016
  • Вы пытаетесь сделать многоадресную рассылку? 17.08.2016
  • @SergeBallesta нет, просто двусторонняя связь ^_^ 17.08.2016
  • @EJP Так жаль! Меня не волнует, какой локальный порт использует клиент. Просто попробуйте сделать несколько подключений из сокета к разным серверам, возможно, это невозможно. Проблема в том, что я не знаю, как этого добиться, если это возможно, и я хочу знать, существует ли какой-либо другой способ, кроме SO_REUSEADDR. 17.08.2016
  • Вы не можете выполнять несколько подключений из одного сокета. Вы можете сделать это из одного порта, но только если это позволяет ядро ​​и если у вас есть для этого требования. Чтобы добиться множественных подключений к серверу, нужно забыть о локальном порте. Не привязывайте сокет и не упоминайте его локальный адрес или порт при его создании или подключении. Вы все еще не заявили о реальной проблеме, и вы все еще не рассказали нам о своем неестественном отвращении, так что SO_REUSEADDR. Не то чтобы это актуально. Здесь нет проблемы, которую нужно решить. 18.08.2016
  • @EJP Я неправильно понял что-то раньше. Теперь с точки зрения сервера сервер accept() получает клиентские соединения, а затем создает (возвращает) новый сокет для каждого соединения. Все эти новые созданные сокеты, созданные системой, привязаны к одному и тому же порту. И наоборот, для клиента также должно быть несколько сокетов, привязанных к одному и тому же порту. То, что сокеты используют один и тот же порт на стороне сервера, выполняется естественным образом и легко достигается, но на стороне клиента это трудно реализовать (ни одна функция не может возвращать новый сокет, используя тот же порт, к которому привязаны другие сокеты). 18.08.2016
  • @EJP Что касается SO_REUSEADDR, он используется в период TIME_WAIT и чаще всего используется на стороне сервера. Я ожидаю создания нескольких клиентских сокетов под одним и тем же портом для одновременного подключения к другому серверу, а не последовательно. SO_REUSEPORT может это сделать, но SO_REUSEPORT не полностью поддерживается на всех платформах (возможно, я ошибаюсь). Производным является вопрос о том, сколько теоретически TCP-соединений с серверами может поддерживать клиент. Меньше 65535 или больше 65535 (до 2^64)? 18.08.2016

Ответы:


1

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

Если вы хотите отправить одно сообщение, и вы хотите, чтобы это сообщение было получено двумя серверами, вам нужна многоадресная рассылка. многоадресная рассылка может использовать только UDP (не TCP) и один из специальных многоадресных адресов (от 224.0.0.0 до 239.255.255.255), который не указан как зарезервировано IANA.

17.08.2016
  • почему один сокет может быть подключен только к одному месту назначения? Одно соединение состоит из сокета (192.168.1.101:9999) и одного места назначения (192.168.1.101:12345); другое соединение состоит из сокета (192.168.1.101:9999) и адресата (192.168.1.101:12346). Два соединения различны. Учитывая, что один единственный сокет может быть подключен к нескольким адресатам, один сокет может сообщать об этих соединениях, отправлять разные сообщения на серверы, получать сообщения, отправленные серверами, и нет никаких проблем. Почему сокет может подключаться только к одному месту назначения? Почему этот предел существует? 17.08.2016
  • @Qoobee: вы путаете адрес (IP + порт) и сокет. Сокет — это дескриптор, который позволяет вам манипулировать обменом между двумя адресами. TCP-соединение — это долгоживущее соединение между двумя адресами (src и dst IP+port), которым вы управляете через сокет. Почему это так? Потому что именно так это было реализовано в BSD4... 17.08.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..