Вам нужно использовать селектор.Сначала создайте селектор для получения событий:
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) (или один из его вариантов), чтобы подготовить данные на канале до тех пор, пока он не будет пустым.
Запись - это биЭто сложнее, так как вы обычно хотите буферизовать данные для записи, пока не получите событие записи:
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);
}
}
Обратите внимание, что вам понадобится соответствующий код для управления буфером в классе, если он заполнитсяили изменить его соответствующим образом в методе отложенной записи, если не все данные в буфере записаны в сокет, а также различные исключения, которые могут быть выброшены во время процесса.Надеюсь, это поможет вам начать.