NIOを使用して複数の同時接続を処理するマルチスレッド ゲームサーバー アプリケーションを作成しました。残念ながら、このサーバーは、最初のユーザーが接続するとすぐに、そのユーザーが実際にデータを送受信していない場合でも、1 つのコアで完全な CPU 負荷を発生させます。
以下は、私のネットワーク処理スレッドのコードです (読みやすくするために重要な部分に省略されています)。このクラスClientHandler
は、ゲーム メカニクスのネットワーク抽象化を行う独自のクラスです。以下の例の他のすべてのクラスはjava.nio
.
ご覧のとおり、while(true)
ループを使用しています。それについての私の理論は、キーが書き込み可能な場合、selector.select()
すぐに返されclientHandler.writeToChannel()
て呼び出されるというものです。しかし、ハンドラーが何も書き込まずに戻ると、キーは書き込み可能なままになります。次に、 select がすぐに再度呼び出され、すぐに戻ります。だから私は忙しいスピンを得ました。
clientHandlers によって送信されるデータがない限りスリープ状態になるようにネットワーク処理ループを設計する方法はありますか? 私のユースケースでは低レイテンシーが重要であることに注意してください。そのため、ハンドラーにデータがない場合、任意のミリ秒だけスリープさせることはできません。
ServerSocketChannel server = ServerSocketChannel.open();
server.configureBlocking(false);
server.socket().bind(new InetSocketAddress(port));
Selector selector = Selector.open();
server.register(selector, SelectionKey.OP_ACCEPT);
// wait for connections
while(true)
{
// Wait for next set of client connections
selector.select();
Set<SelectionKey> keys = selector.selectedKeys();
Iterator<SelectionKey> i = keys.iterator();
while (i.hasNext()) {
SelectionKey key = i.next();
i.remove();
if (key.isAcceptable()) {
SocketChannel clientChannel = server.accept();
clientChannel.configureBlocking(false);
clientChannel.socket().setTcpNoDelay(true);
clientChannel.socket().setTrafficClass(IPTOS_LOWDELAY);
SelectionKey clientKey = clientChannel.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);
ClientHandler clientHanlder = new ClientHandler(clientChannel);
clientKey.attach(clientHandler);
}
if (key.isReadable()) {
// get connection handler for this key and tell it to process data
ClientHandler clientHandler = (ClientHandler) key.attachment();
clientHandler.readFromChannel();
}
if (key.isWritable()) {
// get connection handler and tell it to send any data it has cached
ClientHandler clientHandler = (ClientHandler) key.attachment();
clientHandler.writeToChannel();
}
if (!key.isValid()) {
ClientHandler clientHandler = (ClientHandler) key.attachment();
clientHandler.disconnect();
}
}
}