(Обратный вызов) Java ServerSocketChannel SocketChannel

Я пытаюсь изучить Java. Я хотел бы реализовать простое сетевое подключение 4 игры, а также функция чата.

Я хочу, чтобы моя сетевая логика не заблокировалась поэтому после большого исследования, я нашел, что SocketChannel - то, что я после переаттестации мои потребности.

Что не имело смысла, все еще отсутствие Функций обратного вызова в SocketChannels.. Как каждый находит в C#.

Мой запрос в течение этого времени: Как я поставляю данные, полученные форме Чата или Игры (JFrame)?

Некоторое руководство приветствуется.

5
задан iTEgg 21 April 2010 в 18:27
поделиться

1 ответ

Вам нужно использовать селектор. Сначала создайте селектор для приема событий:

Selector selector = Selector.open()

Затем вам нужно зарегистрировать ServerSocketChannel с помощью селектора:

SelectionKey acceptKey = server.register(selector, SelectionKey.OP_ACCEPT);

Затем вам нужно использовать селектор для обработки событий по мере их поступления (вы можете думать об этом как о «обратном вызове»). "часть процесса:

while(true){
  //how many channel keys are available
  int available = selector.select(); 
  //select is blocking, but should only return if available is >0, this is more of a sanity check
  if(available == 0) continue;

  Iterator<SelectionKey> keys = selector.selectedKeys().iterator();
  while(keys.hasNext()){
    SelectionKey key = keys.next();
    keys.remove();
    //someone is trying to connect to the server socket
    if(key.isAcceptable())  doAccept(key); 
    //someone is sending us data
    else if(key.isReadable()) doRead(key); 
    //we are trying to (and can) send data
    else if(key.isWritable()) doWrite(key);
}

Мясо будет в doAccept (), doRead () и doWrite (). Для клавиши принятия клавиша выбора будет содержать информацию для создания нового Socket.

doAccept(SelectionKey key){

//create the new socket
SocketChannel socket = ((ServerSocketChannel)key.channel()).accept(); 
//make it non-blocking as well
socket.configureBlocking(false);

...
//here you would likely have some code to init your game objects / communication protocol, etc. and generate an identifier object (used below).
//and be able to find the socket created above
...

//Since it is non blocking it needs a selector as well, and we register for both read and write events
SelectionKey socketKey = socket.register(selector, SelectionKey.OP_READ|SelectionKey.OP_WRITE);
// so we can identify the events as they come in
socketKey.attach(someSocketIndentifier);
}

Последняя строка добавляет некоторый объект к ключу, чтобы события, полученные от селектора, можно было отнести к соединению (например, это может быть игрок в вашей игре) .Теперь вы можете принимать новые соединения, и вам просто нужно будет читать и писать.

doRead(SelectionKey key){
  //here we retrieve the key we attached earlier, so we now what to do / wheer the data is coming from
  MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment();
  //This is then used to get back to the SocketChannel and Read the Data
  myIdentifier.readTheData();
}

аналогично для записи

doWrite(SelectionKey key){
  //here we retrieve the key we attached earlier, so we now what to do / wheer the data is coming from
  MyIdentifierType myIdentifier = (MyIdentifierType)key.attachment();
  //This is then used to get back to the SocketChannel and Read the Data
  myIdentifier.getSocketHandler().writePendingData();
}

Чтение довольно прямолинейно, вы просто создаете ByteBuffer, а затем вызываете чтение SocketChannels (ByteBuffer) (или один из его вариантов), чтобы подготовить данные на канале до тех пор, пока он не станет пустым.

Запись немного сложнее, так как вы обычно хотите буферизовать данные для записи, пока вы не получите запись e event:

class MyNetworkClass{
  ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
  SocketChannel commchannel; //from the server accept processing

  ...

  public void write(byte[] data){
    //here the class writeBuffer object is filled with the data
    //but it isn't actually sent over the socket
    ...
  }

  public void writePendingData(){
    //here actually write the data to the socket
    commchannel.write(writeBuffer);
  }
}

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

14
ответ дан 18 December 2019 в 13:12
поделиться
Другие вопросы по тегам:

Похожие вопросы: