view test/ServerSample.java @ 481:607f1dfe2b80

add comment
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Fri, 15 Oct 2010 19:47:53 +0900
parents 4b535bef903a
children
line wrap: on
line source

package test;
import java.io.IOException;
import java.nio.channels.*;
import java.net.*;

import rep.REPCommand;
import rep.REPCommandPacker;
import rep.channel.REPPack;
import rep.channel.REPSelectionKey;
import rep.channel.REPSelector;
import rep.channel.REPServerSocketChannel;
import rep.channel.REPSocketChannel;

public class ServerSample
{
	// client も書いて、standalone example として動くべき
	public static void main(String[] argv)
	throws Exception
	{
		// Thread base のSimulationか、実際のSocketかの選択
		REPServerSocketChannel.isSimulation = false;
		// セレクタの用意
		REPSelector<REPCommand> selector = REPSelector.create();

		REPPack<REPCommand> pack = new REPCommandPacker();
		// サーバソケットチャンネルを作成。5100番ポートを受付ポートに指定
		// (非ブロックモードに設定:重要)
		REPServerSocketChannel<REPCommand> serverSocketChannel = REPServerSocketChannel.<REPCommand>open(pack);
		serverSocketChannel.configureBlocking(false);
		serverSocketChannel.socket().setReuseAddress(true);
		try {
			serverSocketChannel.socket().bind(new InetSocketAddress("::",5100));
		} catch (SocketException e) {
			// some system does not support "::"
			serverSocketChannel.socket().bind(new InetSocketAddress(5100));
		}

		// セレクタにサーバソケットチャンネルを登録。サーバへの受付を監視
		serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

		// セレクタにイベントが通知されるごとに処理
		while (true) {

			// セレクタにイベントが発生するまでブロック
			// select のreturn valueは信用しない。selectedKeys()を使う。
			selector.select();

			// 獲得したイベントごとに処理を実行
			for (REPSelectionKey<REPCommand> selectionKey : selector.selectedKeys1()) {
				// java.nio だと for 文では動かないが、REPSocketChannel では動く
				// 
			    //for (Iterator<SelectionKey> it = keys.iterator();it.hasNext(); ) {
			    //    SelectionKey k = it.next();
				//	newKeys.add(new REPSelectionKey<P>(k,this));
			    //    it.remove();
				//}
				// と書く必要がある。

				// サーバの受付処理: 
				// イベントが受付可能である場合、受け付けるべき対象があれば
				// セレクタに取得したソケットチャンネルを登録
				if (selectionKey.isAcceptable()) {

					// サーバソケットチャンネルからソケットチャンネルを獲得
					// ソケットチャンネルを経由してクライアントと通信できる
					//SocketChannel socketChannel = serverSocketChannel.accept();
					REPSocketChannel<REPCommand> socketChannel;
					socketChannel = selectionKey.accept(pack);

					// 接続先がなくてもここに処理が飛ぶことがある。対象が
					// nullの場合は処理を抜ける
					if (null == socketChannel) continue;

					// ソケットチャンネルを非ブロックモードに設定(重要)し、
					// セレクタに読み込みを対象として登録
					socketChannel.configureBlocking(false);
					socketChannel.register(selector, SelectionKey.OP_READ);
					socketChannel = null;
				}

				// クライアントとの通信処理
				// 読込み可能である場合、内容物を読みこんで標準出力に表示。
				// メッセージをクライアントに送信して、コネクションを切断。
				// セレクタから登録を解除
				else if (selectionKey.isReadable()) {

					// 登録されているソケットチャンネルを取得
					REPSocketChannel<REPCommand> socketChannel = 
						selectionKey.channel1();

					REPCommand cmd = null;
					// クライアントからメッセージの受信
					try {
						cmd = socketChannel.read();
					} catch (IOException e) {
						// クライアント側が接続を切断していた場合は、サーバも
						// 接続を切断。セレクタから登録を削除
						selectionKey.cancel(); // これは必要だと思う
						socketChannel.close(); // たぶん不要
					}
					if (cmd==null) {
						// 読み込むべきメッセージは届いていないので処理を飛ばす
						// こういう場合もある
						continue;
					}
					// クライアントからメッセージを取得し、標準出力へ
					System.out.print("EEE: " + cmd);

					// クライアントへメッセージを送信
					// copy or do not modify after the write
					// In the simulation, object is directly passed
					// to the client
					cmd = new REPCommand(cmd);
					cmd.setString("This is the answer.");
					socketChannel.write(cmd);

					// クライアントとの接続を切断。セレクタから登録を削除
					socketChannel.close();
					//break;
				}
				System.out.println(selectionKey.toString());
			}
		}
	}
}