java: одиночный сокет при операции чтения-записи. Полный дуплекс

#java #sockets #duplex #socketchannel

#java #сокеты #дуплекс #socketchannel

Вопрос:

Я должен реализовать отправку данных с определенного исходного порта и в то же время прослушивать этот порт. Полный дуплекс. Кто-нибудь знает, как это реализовать на Java. Я попытался создать отдельный поток для прослушивания входного потока сокета, но это не работает. Я не могу привязать ServerSocket и клиентский сокет к одному и тому же исходному порту и то же самое с netty. Есть ли какое-либо решение для скучного дуплекса?

     init(){
    socket = new Socket(InetAddress.getByName(Target.getHost()), Target.getPort(), InetAddress.getByName("localhost"), 250);
    in = new DataInputStream(socket.getInputStream());
    out = new DataOutputStream(socket.getOutputStream());
    }

     private static void writeAndFlush(OutputStream out, byte[] b) throws IOException {
        out.write(b);
        out.flush();
      }


    public class MessageReader implements Runnable {

        @Override
        public void run() {
//this method throw exception EOF
          read(in);

          }
private void read(DataInputStream in){
 while (isConnectionAlive()) {
          StringBuffer strBuf = new StringBuffer();
          byte[] b = new byte[1000];
          while ((b[0] = bufferedInputStream.read(b)) != 3) {
            strBuf.append(new String(b));
          }
          log.debug(strBuf.toString());
        }
}
        }
  

Комментарии:

1. Когда вы записываете на определенный порт, это не your порт.. вы записываете на порт целевой машины, если только вы не говорите, что пишете для себя? Начните с прослушивателя…

2. новый сокет (remoteAddress, RemotePort, localAddress, LocalPort). Мне нужно прослушивать локальный порт и одновременно отправлять сообщения с этого порта. ServerSocket не может отправлять сообщения. Обычный сокет не может прослушиваться или, по крайней мере, я не знаю, как это реализовать

3. Вам нужен только один сокет для чтения и записи. Вы можете вызвать Socket.getInputStream для чтения и Socket.getOutputStream для записи. Однако чтение из входного потока является блокирующим вызовом, поэтому вы можете захотеть выполнить это в отдельном потоке. Покажите нам часть вашего кода, чтобы мы могли увидеть, что вы уже пробовали.

Ответ №1:

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

Полный дуплекс довольно просто выполнить с помощью NIO:

  1. Создайте Channel для своего Socket в неблокирующем режиме
  2. Добавьте чтение в интересующие операции
  3. Переход в спящий режим с помощью метода Selector ‘s select()
  4. Считывать любые читаемые байты, записывать любые доступные для записи байты
  5. Если запись завершена, удалите запись из интересующих операций
  6. ПЕРЕХОД 3.
  7. Если вам нужно записать, добавьте байты в буфер, добавьте запись в интересующие операции и активируйте селектор. (немного упрощенный, но я уверен, что вы сможете найти свой путь вокруг Javadoc)

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

Ответ №2:

Я столкнулся с тем же вопросом и решил ответить на него сам. Я хотел бы поделиться с вами, ребята, репозиторием кода. Это действительно просто, вы можете понять, как заставить ваши вещи работать. Это сложный пример. Шаги случайно выглядят как решение Ордуса.

https://github.com/khanhhua/full-duplex-chat

Не стесняйтесь клонировать! Это моя домашняя работа на выходные.

Ответ №3:

Основной поток:

  • Создайте фоновый поток (потоки), который будет подключаться к любым целевым машинам.
    • Эти потоки будут подключаться к целевым машинам, передавать данные и умирать
  • Создайте бесконечный цикл
    • Прослушивание входящих подключений.
      • Отключите любое соединение для обработки ввода-вывода

Классы:

  • Сервер
    • Прослушивает входящие соединения и потоки от объекта клиента
  • Клиент
    • Этот класс создается на сервере, принимающем входящее соединение, TcpClient или NetClient (я забыл, как это называется Java) используется для отправки данных. По завершении он умирает.
  • Цель
    • Создается во время запуска и подключается к определенной цели и отправляет данные.
    • после завершения он умирает.

Комментарии:

1. Я не отправляю ответ клиенту. Я должен иметь возможность отправлять сообщения на любой сервер и прослушивать prt, который я использовал для отправки своего сообщения

2. хорошо, известен ли список серверов, к которым вы подключаетесь и отправляете данные? я предполагаю, что это должно было бы быть

3. давайте предположим, что у нас есть некоторый сервер с именем Target с известными targetHost и targetPort. Я подключаюсь и отправляю сообщения к цели с подключением типа new Socket (remoteAddress, RemotePort, myHost, myPort), и наоборот, цель отправляет на мой порт myPort, поэтому я должен постоянно прослушивать myPort. Это не обмен запросами-ответами. Цель и я отправляем сообщения друг другу в случайном порядке

4. звучит прямолинейно … основной поток — слушатель… затем создайте поток для подключения к этой «цели»…

5. вы имеете в виду новый ServerSocket (myport) и create listener? Тогда как отправить сообщение на определенный порт без предварительного запроса? Я не могу создать другой сокет на том же локальном порту