Переадресация входящих TCP-команд в функцию? - PullRequest
3 голосов
/ 26 января 2009

В Java, как бы вы настроили слушатель сокета, который прослушивал сокет для серии байтов, представляющих команду, и при получении вызывал метод, который анализировал входящие данные и вызывал соответствующую команду?

Пояснение:

Моя проблема не в обработке команд (которые также могут быть кодами ошибок или ответами на команды от сервера), а в создании сокета и его прослушивании.

Больше разъяснений:

Я хочу подражать следующей строке .Net (C #) кода:

_stream.BeginRead(_data,0, _data.Length, new  
    AsyncCallback(this.StreamEventHandler), _stream);

Где:

  • _stream - это сетевой поток, созданный из сокета
  • _data - массив байтов длиной 9
  • this.StreamHandler - это делегат (указатель на функцию), который выполняется при чтении данных.

Я переписываю библиотеку из C # в Java, и компонент, который я сейчас пишу, передает команды на сервер через TCPIP, но также должен иметь возможность всплывать события / ответы для уровня над ним.

В C # это кажется тривиальным и выглядит все менее и менее в Java.

Ответы [ 8 ]

1 голос
/ 26 января 2009

Есть небольшой метод main, который устанавливает сокет и прослушивает входящие соединения. Передайте каждое соединение рабочему объекту (возможно, в его собственном потоке).

Рабочий объект должен иметь два API: сервер и клиент. Клиентский API получает соединение и считывает с него данные, серверный API берет соединение и записывает в него данные.

Мне нравится хранить эти два в одном классе, потому что это значительно упрощает синхронизацию этих двух. Используйте вспомогательный класс для кодирования / декодирования данных для передачи, поэтому у вас есть единая точка, чтобы решить, как передавать целые числа, команды, параметры и т. Д.

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

1 голос
/ 26 января 2009

Начиная с моего другого ответа : Специальная часть, которую вы запрашиваете, входит в раздел: "Волшебство здесь". Это можно сделать разными способами, но один из них:

final InputStream in = socket.getInputStream();
// This creates a new thread to service the request.
new Thread(new Runnable(){
  public void run(){
    byte[] retrievedData= new byte[ITEM_LENGTH];
    in.read(retrievedData, 0, ITEM_LENGTH);
    in.close();

    // Here call your delegate or something to process the data
    callSomethingWithTheData(retrievedData);
  }
}).start();
0 голосов
/ 27 января 2009

Вы можете создать перечисление с одним членом для каждой команды

interface Comamnd {
    // whatever you expect all command to know to perform their function
    void perform(Context context);
}

enum Commands implements Command{
   ACTIONONE() {
        void perform(Context context) {
             System.out.println("Action One");
        }
   },
   ACTIONTWO() {
        void perform(Context context) {
             System.out.println("Action Two");
        }
   }
}

// initialise
DataInputStream in = new DataInputStream(socket.getInputStream());

// in a loop
byte[] retrievedData= new byte[ITEM_LENGTH];
in.readFully(retrievedData);
String command = new String(retrievedData, 0);
Commands.valueOf(command).perform(context);
0 голосов
/ 26 января 2009

Чтобы создать прослушивание сокета, очень наивным способом:

    mServerSocket = new ServerSocket(port);

    listening = true;

    while (listening) {

      // This call blocks until a connection is made
      Socket socket = serverSocket.accept();

      OutputStream out = socket.getOutputStream();
      InputStream in = socket.getInputStream();

      // Here you do your magic, reading and writing what you need from the streams
      // You would set listening to true if you have some command to close the server
      // remotely

      out.close();
      in.close();
      socket.close();
   }

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

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

0 голосов
/ 26 января 2009

Любой наивный подход, скорее всего, не будет хорошо масштабироваться.

Подумайте об использовании REST-подхода с подходящим небольшим веб-сервером. Причал, как правило, хороший выбор.

0 голосов
/ 26 января 2009

Это должно помочь. Урок 1: Связь через сокет

0 голосов
/ 26 января 2009

TCP-соединение предоставляет вам один InputStream и один OutputStream. Вы можете просто непрерывно опрашивать InputStream для следующей команды (и ее входов) в выделенном потоке. ByteBuffer.wrap(byte[] array) может быть полезно при интерпретации байтов как символов, целых, длинных и т. Д. Вы также можете передавать объекты, используя serialization .

0 голосов
/ 26 января 2009

Я бы

  1. помещает каждую команду в class своей собственной, где каждый класс реализует определенный interface (например, Command)

  2. создает Map<String,Command>, который содержит таблицу поиска из каждой командной строки для экземпляра класса, реализующего эту команду

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...