EchoServant - .nio ver -
参考
- Javaネットワークプログラミングの真髄
- Socketのクローズによるクライアント・サーバの動作について
- オブジェクトの送受信について
- ロギングについて
プログラム
備考
- サーバ・クライアントは実行後選択
- 多重接続対応
- クライアントは一定期間ごとにメッセージを送り続け,規定時間後終了
- サーバは起動し続ける(クライアントを待ち続ける)
コード
Main
public class Main { private static MyLog l = new MyLog(); private static BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); private static final int SERVER_PORT = 5555; private static final String LOCAL_IP = "192.168.0.216"; public static void main(String[] args) throws IOException { l.l("'s'erver or 'c'lient>>"); String mode = br.readLine(); if (mode.equals("s")) { server(); } else if (mode.equals("c")) { client(); } } /* server lunch */ static private void server() throws IOException { l.il("Server start"); new Server(SERVER_PORT).start(); } /* client lunch*/ static private void client() throws IOException { l.il("Client start"); l.il("Server ip: " + LOCAL_IP); l.il("Server port: " + SERVER_PORT); new Client(LOCAL_IP, SERVER_PORT).start(); } }
Server
class Server { public static final int BUFFER_SIZE = 8192; public static final int TIMEOUT = 5 * 1000; // 5 sec private MyLog l = new MyLog(); private ServerSocketChannel serverSocketChanel; private Selector selector; private int port; public Server(int port) throws IOException { this.port = port; selector = Selector.open(); acceptableSocketChannelRegister(); } public void start() { try { while (selector.keys().size() > 0) { int selectedKeyCount = 0; if ((selectedKeyCount = selector.select(TIMEOUT)) <= 0) { l.il("Select Time out (" + TIMEOUT + " ms): selectedKeyCount: " + selectedKeyCount); continue; } else { l.il("Select: selectedKeyCount: " + selectedKeyCount); } Iterator selectedKeysIterator = selector.selectedKeys().iterator(); while (selectedKeysIterator.hasNext()) { SelectionKey key = (SelectionKey)selectedKeysIterator.next(); selectedKeysIterator.remove(); if (!key.isValid()) { l.il("Received invalid key: " + key); continue; } if (key.isAcceptable()) { l.il("Selcted key: accept"); handleAcceptable(key); } if (key.isReadable()) { l.il("Selcted key: read"); handleReadable(key); } if (key.isWritable()) { l.il("Selcted key: write"); handleWritable(key); } if (key.isConnectable()) { l.il("Selcted key: connect"); //handleConnectable(key); } } } } catch (Exception e) { } } private void handleAcceptable(SelectionKey key) { try { ServerSocketChannel srvCh = (ServerSocketChannel)key.channel(); SocketChannel channel = srvCh.accept(); channel.configureBlocking(false); ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); channel.register(key.selector(), SelectionKey.OP_READ, buffer); l.il("Connected client: " + channel); acceptableSocketChannelRegister(); } catch(Exception e) { } } private void handleReadable(SelectionKey key) { try { SocketChannel channel = (SocketChannel)key.channel(); ByteBuffer buffer = (ByteBuffer)key.attachment(); int count = channel.read(buffer); if (count < 0) { key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); l.il("Close client(read): " + channel); //channel.close(); return; } else if (count == 0) { key.interestOps(key.interestOps() & ~SelectionKey.OP_READ); } key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); handleWritable(key); } catch(Exception e) { } } private void handleWritable(SelectionKey key) { try { SocketChannel channel = (SocketChannel)key.channel(); ByteBuffer buffer = (ByteBuffer)key.attachment(); buffer.flip(); l.ll("Echo message: " + decode(buffer.duplicate())); int count = channel.write(buffer); buffer.compact(); if (count < 0) { key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); l.il("Close client(write): " + channel); //channel.close(); return; } else if (count == 0) { key.interestOps(key.interestOps() & ~SelectionKey.OP_WRITE); } } catch(Exception e) { } } private void acceptableSocketChannelRegister() throws IOException { serverSocketChanel = ServerSocketChannel.open(); serverSocketChanel.configureBlocking(false); serverSocketChanel.socket().bind(new InetSocketAddress(port)); serverSocketChanel.register(selector, serverSocketChanel.validOps()); l.il("Server status: " + serverSocketChanel.socket().toString()); l.il("ServerSocketChannel valid ops: " + serverSocketChanel.validOps()); } private String decode(ByteBuffer buffer) throws CharacterCodingException { Charset charset = Charset.forName("UTF-8"); CharsetDecoder decoder = charset.newDecoder(); return decoder.decode(buffer).toString(); } }
Client
class Client { public static final int BUFFER_SIZE = 8192; public static final int TIMEOUT = 5 * 1000; // 5 sec private MyLog l = new MyLog(); private Socket socket; public Client(String ip, int port) { try { this.socket = new Socket(); socket.setReceiveBufferSize(BUFFER_SIZE); socket.connect(new InetSocketAddress(ip, port)); socket.setSendBufferSize(BUFFER_SIZE); socket.setSoTimeout(TIMEOUT); } catch (Exception e) { } finally { } } public void start() { handleConversation(socket); } private void handleConversation(Socket socket) { BufferedReader br = null; BufferedWriter bw = null; try { br = new BufferedReader(new InputStreamReader(socket.getInputStream())); bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream())); // 500ms間隔で書き込み for (int i = 0; i < 10; i++) { String sendLine = "Hello from Client. i=" + i + "\n"; bw.write(sendLine); bw.flush(); String receavedLine = br.readLine(); l.ll("Sended: " + sendLine); l.ll("Received: " + receavedLine); Thread.sleep(2000); l.ll("--"); } } catch (Exception e) { } finally { try { bw.close(); br.close(); socket.close(); } catch (IOException e) { } l.il("End client"); } } }
MyLog
public class MyLog { public MyLog() { } public void l(String s) { System.out.print(s); } public void ll(String s) { System.out.println(s); } public void i(String s) { System.err.print("INFO: " + s); } public void il(String s) { System.err.println("INFO: " + s); } public void w(String s) { System.err.print("WERNING: " + s); } public void wl(String s) { System.err.println("WERNING: " + s); } public void s(String s) { System.err.print("SEVERE: " + s); } public void sl(String s) { System.err.println("SEVERE: " + s); } }