キー入力とソケット通信を非同期に取り扱いたく、java.nioを使ってお試しプログラムを作ってみました。キー入力する側をstdinPipe、ソケット通信する側をSocketChannelとしています。
stdinPipeでキー入力を受け取った時、SocketChannelにそのバッファを書き込み、送信タイミングを作るためにSelectionKey.interestOps(SelectionKey.OP_WRITE);するようにコーディングしています。
実行した結果、SocketChannel.write()は成功(送信バイト数が返る)しているように見えるのですが、ネットワーク上にデータが流れず、又、SelectionKey.OP_WRITEが無限ループしてしまいます。
あるチャネル(stdinPipe)から、他のチャネル(SocketChannel)を発火させる正しい方法は、どのようなコードになるのでしょうか?何か良い例があればご教授いただけないでしょうか。
以下、期待通り動かないプログラムを載せておきます。
Main:
java:
1 public static void main(String[] args) throws Exception { 2 Selector selector = Selector.open(); 3 4 final Socket socket = new Socket(); 5 SocketChannel socketChannel = SocketChannel.open(); 6 socketChannel.configureBlocking(true); 7 socketChannel.connect(new InetSocketAddress("localhost", 50000)); 8 System.out.println("connected."); 9 socketChannel.configureBlocking(false); 10 IOHandler ioHandler = new IOHandler(); 11 SelectionKey sckey = socketChannel.register( 12 selector, 13 SelectionKey.OP_READ, 14 ioHandler 15 ); 16 17 SystemInPipe stdinPipe = new SystemInPipe(); 18 SelectableChannel stdinChannel = stdinPipe.getStdinChannel(); 19 stdinChannel.register( 20 selector, 21 SelectionKey.OP_READ, 22 new StdinHandler(sckey) 23 ); 24 stdinPipe.start(); 25 26 System.out.println("selecting..."); 27 while(selector.select() > 0) { 28 Set keys = selector.selectedKeys(); 29 30 for (Iterator it = keys.iterator(); it.hasNext(); ) { 31 SelectionKey key = (SelectionKey)it.next(); 32 it.remove(); 33 Handler handler = (Handler)key.attachment(); 34 handler.handle(key); 35 } 36 } 37 38 }
stdinPipe:
java:
1 2package example; 3 4import java.io.DataOutputStream; 5import java.io.IOException; 6import java.net.Socket; 7import java.nio.ByteBuffer; 8import java.nio.channels.ClosedChannelException; 9import java.nio.channels.ReadableByteChannel; 10import java.nio.channels.SelectionKey; 11 12public class StdinHandler implements Handler { 13 private SelectionKey selectionKey = null; 14 15 public StdinHandler(SelectionKey selectionKey) { 16 this.selectionKey = selectionKey; 17 } 18 19 @Override 20 public void handle(SelectionKey key) throws ClosedChannelException, IOException { 21 ByteBuffer buffer = ByteBuffer.allocate(32); 22 ReadableByteChannel channel = (ReadableByteChannel) key.channel(); 23 if (channel.read(buffer) <= 1) { 24 System.out.println("program completed."); 25 channel.close(); 26 System.exit(-1); // @TODO 段取りを踏んだ終わり方に変更する 27 } 28 buffer.flip(); 29 while (buffer.hasRemaining()) { 30 System.out.print((char) buffer.get()); 31 } 32 System.out.println(); 33 34 buffer.flip(); 35 if (selectionKey != null) { 36 IOHandler handler = (IOHandler)selectionKey.attachment(); 37 handler.setBuffer(buffer); 38 selectionKey.interestOps(SelectionKey.OP_WRITE); 39 } 40 41 buffer.clear(); 42 } 43 44}
socketChannel:
java
1package example; 2 3import java.io.IOException; 4import java.nio.ByteBuffer; 5import java.nio.channels.ClosedChannelException; 6import java.nio.channels.SelectionKey; 7import java.nio.channels.SocketChannel; 8import java.util.ArrayList; 9import java.util.List; 10 11import javax.xml.bind.DatatypeConverter; 12 13/* 14 * @see 出典: http://itpro.nikkeibp.co.jp/article/COLUMN/20060515/237871/ 15 */ 16public class IOHandler implements Handler { 17 private final static int BUFFER_SIZE = 4096; 18 19 private List<ByteBuffer> buffers; 20 21 public IOHandler() { 22 // 読み込んだデータを格納するためのリストの初期化 23 buffers = new ArrayList<ByteBuffer>(); 24 } 25 26 public void setBuffer(ByteBuffer buffer) { 27 buffers.add(buffer); 28 } 29 30 public void handle(SelectionKey key) 31 throws ClosedChannelException, IOException { 32 SocketChannel channel = (SocketChannel)key.channel(); 33 34 // 読みこみ可であれば、読みこみを行う 35 if (key.isReadable()) { 36 read(key); 37 } 38 39 // 書きこみ可であれば、書きこみを行う 40 if (key.isWritable() && key.isValid()) { 41 write(key); 42 } 43 } 44 45 private void read(SelectionKey key) 46 throws ClosedChannelException, IOException { 47 SocketChannel channel = (SocketChannel)key.channel(); 48 49 // 読みこみ用のバッファの生成 50 ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE); 51 52 // 読みこみ 53 channel.read(buffer); 54 55 // フリップしてからリストに追加 56 buffer.flip(); 57 buffers.add(buffer); 58 59 if (key.interestOps() 60 != (SelectionKey.OP_READ | SelectionKey.OP_WRITE)) { 61 // 読みこみ操作に対する監視を行う 62 key.interestOps(SelectionKey.OP_READ 63 | SelectionKey.OP_WRITE); 64 } 65 } 66 67 private void write(SelectionKey key) 68 throws ClosedChannelException, IOException { 69 SocketChannel channel = (SocketChannel)key.channel(); 70 71 if (!buffers.isEmpty()) { 72 // リストが空でなければ、先頭のバッファを取り出し 73 // 書きこみを行う 74 ByteBuffer buffer = buffers.get(0); 75 int size = channel.write(buffer); 76 System.out.println("write size= " + size); 77 String hexString = DatatypeConverter.printHexBinary(buffer.array()); 78 System.out.println(hexString); 79 80 key.interestOps(SelectionKey.OP_READ); 81 82 try { 83 Thread.sleep(1000); 84 } catch (InterruptedException e) { 85 // TODO Auto-generated catch block 86 e.printStackTrace(); 87 } 88 89 // 書きこみが終わったバッファは削除する 90 buffers.remove(0); 91 } else { 92 // 書きこむデータがなければ、書きこみ操作の監視をやめる 93 key.interestOps(SelectionKey.OP_READ); 94 } 95 } 96}
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2015/08/04 23:08 編集