皆さん、こんにちは!
私の質問は NIO ベースのサーバーに関するもので、私の状況は次のとおりです。サーバーは、それぞれ 100 個のメッセージを送信する 100 個のクライアント (100 個のクライアント スレッド) からメッセージを読み取ります。したがって、メッセージの総数は 100x100 = 10000 です。サーバーに着信メッセージ カウンターがあり、クライアントからメッセージを読み取った後に増加します。メッセージを読んだだけで、サーバーは約 9200 件のメッセージを読み取ります。Simulationg サービスの遅延にダミー ループを追加すると、サーバーは驚くべきことに 10000 メッセージすべてを処理します。
私の期待は次のようなものです-OK、サーバーはわずかな遅延でも10000メッセージすべてを読み取ることができます. したがって、この遅延がなければ、サーバーはおそらくより多くのメッセージを読み取ることができます (より多くのクライアントにサービスを提供できます)。しかし、ほら、これは間違っています。遅滞なく事態は悪化します。ここで、私のアーキテクチャについて説明しました。現在のロジックの唯一の変更は、クライアントの受け入れとメッセージの読み取りを 2 つの異なるスレッドに分割することです。1 つのセレクターは 1 つのスレッドでクライアントを受け入れ、2 つ目のセレクターは接続されたクライアントからのメッセージを他のスレッドで待機します。
クライアントコード
public class TCPClient implements Runnable{
private String name;
private static TCPClient[] clients;
private static Thread[] threads;
private int counter = 0;
public TCPClient(String name)
{
this.name = name;
this.counter = 0;
}
public static void main(String[] args) throws Exception
{
clients = new TCPClient[100];
threads = new Thread[100];
for(int i=0;i<100;i++)
{
clients[i] = new TCPClient("thread # "+Integer.toString(i));
threads[i] = new Thread(clients[i]);
threads[i].start();
// Thread.sleep(500);
}
for(int i=0;i<100;i++)
{
threads[i].join();
}
for(int i=0;i<100;i++){
System.out.println("counter = "+clients[i].counter);
}
}
@Override
public void run()
{
Socket socket = null;
OutputStream out = null;
try
{
socket = new Socket();
socket.connect(new InetSocketAddress("192.168.3.109",2345), 0);
out = socket.getOutputStream();
byte[] bytes;
while(counter < 100)
{
counter++;
bytes = (name+ ", message # "+Integer.toString(counter)+System.lineSeparator()).getBytes();
// System.out.println(counter);
out.write(bytes);
out.flush();
Thread.sleep(200);
}
}
catch(Exception ex)
{
System.out.println(name+" "+Integer.toString(counter));
ex.printStackTrace(new PrintStream(System.out));
System.out.println();
}
finally
{
if(socket!=null && out!=null)
{
try
{
socket.close();
out.close();
}
catch(Exception ex)
{
System.out.println("client close error");
}
}
}
}
}
サーバーコード(メッセージ読み取り部分)
@Override
public void run()
{
isRunning = true;
int acc = 0;
boolean error = false;
while (isRunning) {
try
{
selector.select();
Set keys = selector.selectedKeys();
Iterator it = keys.iterator();
while(it.hasNext())
{
SelectionKey key = (SelectionKey)it.next();
if (key.isReadable())
{
//readMessage(key);
//key.cancel();
// ByteBuffer bbb = ByteBuffer.allocate(2048);
// key.cancel();
curTime = System.currentTimeMillis();
SocketChannel sc = (SocketChannel) key.channel();
// System.out.println("before reading");
bb.clear();
int x = sc.read(bb);
if(x==-1)
{
key.cancel();
//System.out.println("cancelling key");
continue;
}
counter++;
// bb.flip();
//System.out.print(decoder.decode(bb).toString());
// Thread.sleep(20);
long sum=0;
for(int dummy=0;dummy<250000;dummy++)
{
sum += dummy;
// sum %= 1005;
}
long delta = System.currentTimeMillis() - curTime;
serviceTime += delta;
if(counter>9000)
{
System.out.println("recieved messages count = "+counter);
System.out.println("one message service time = "+delta+" milliseconds");
System.out.println("total service time = "+serviceTime+" milliseconds");
System.out.println("sum = "+sum); //11 249 925 000
}
// selector.wakeup();
//key.interestOps(SelectionKey.OP_READ);
}
}
keys.clear();
}
catch (Exception ex)
{
error = true;
System.out.println("error in recieving messages "+ex.getMessage());
ex.printStackTrace(new PrintStream(System.out));
// logger.println("error in recieving messages "+ex.getMessage());
// logger.flush();
}
finally
{
//if(error) // !!!!!!!!!!! DO NOT STOP THE SERVER EDIT IT LATER
//stopServer();
}
}
}
おそらく役立つ情報です。クライアント側での 2 つのメッセージ間の遅延は 200 ミリ秒です。ダミー ループが 200000 ~ 220000 回の反復を行うと、サーバーは完全に機能します。ところで、200000 回の反復は約 200 ミリ秒です。クライアント数が 100 であるため、1 回の select() の遅延は 100*200000 = 200 万回の反復 - 最近の PC では 200 ミリ秒です。ダミー ループの繰り返しが 200000 未満の場合、サーバーは最大 9200 のメッセージを読み取ります。そのような奇妙な行動の理由は何ですか?