2013-03-06 76 views
0

我使用SocketChannel從客戶端的服務器接收TCP流。例如:如何切換socketchannel的阻塞模式?

Selector selector=Selector.open(); 
SocketChannel mychannel=SocketChannel.open(new InetSocketAddress(ip,port)); 
channel.configureBlocking(false); 
SelectionKey channelkey=channel.register(selector,SelectionKey.OP_READ); 

然後,我可以使用selector.select()方法來處理讀取問題。

while(true){ 
    if(selector.select()!=0){ 
     Iterator<SelectionKey> it=selector.selectedKeys().iterator(); 
     while(it.hasNext()){ 
     SelectionKey key=it.next(); 
     it.remove(); 
     if(key.isReadable()){ 
      if(key.equals(channelkey)){ 

       //concrete handle 
       ... 
      } 
     } 
     } 
    } 
} 

混凝土手柄,考慮到我想使用的InputStream(我想讀的流線)從服務器端接收TCP流,有兩個methods.One使用channel.socket(),另一種是使用渠道。這裏我用channel.socket(),例如:

SocketChannel channel = (SocketChannel) key.channel(); 
key.cancel(); 
channel.configureBlocking(true); 
InputStream ins = Channels.newInputStream(channel); 
InputStreamReader is = new InputStreamReader(ins,"utf-8"); 
BufferedReader in = new BufferedReader(is); 
String res = in.readLine(); 
while (!res.equals("")) { 
    System.out.println(res); 
    res = in.readLine(); 
} 
     ......① 

好了,現在我讀完TCP流的一個time.In爲了繼續使用選擇,我應該設置通道阻塞模式爲false。

channel.configureBlocking(false); 

的問題是,它結合了渠道和選擇已經canceled.I要註冊mychannel again.What我應該做的關鍵?看來如果我在①上再次使用mychannel.register(selector, SelectionKey.OP_READ),它會拋出Exception

我的run()方法的代碼如下:

try { 
if (selector.select(getTimeout()) != 0) { 
    Iterator<SelectionKey> it = selector.selectedKeys().iterator(); 
    while (it.hasNext()) { 
     SelectionKey key = it.next(); 
     if (key.isReadable()) { 
      SocketChannel channel = (SocketChannel) key.channel(); 
      key.cancel(); 
      channel.configureBlocking(true); 
      InputStream ins = Channels.newInputStream(channel); 
      InputStreamReader is = new InputStreamReader(ins,"utf-8"); 
      BufferedReader in = new BufferedReader(is); 
      String res = in.readLine(); 
      while (!res.equals("")) { 
       System.out.println("========" + res); 
       res = in.readLine(); 
      } 
      channel.configureBlocking(false); 
      System.out.println(key.isValid()); 
      proxykey=channel.register(selector, SelectionKey.OP_READ); 
     } 
     it.remove(); 
    } 
} 
} catch (IOException ex) { 
    ex.printStackTrace(); 
} 

它拋出的異常是:

Exception in thread "Thread-0" java.nio.channels.CancelledKeyException 
at sun.nio.ch.SelectionKeyImpl.ensureValid(Unknown Source) 
at sun.nio.ch.SelectionKeyImpl.interestOps(Unknown Source) 
at java.nio.channels.spi.AbstractSelectableChannel.register(Unknown Source) 
at java.nio.channels.SelectableChannel.register(Unknown Source) 
at AgentThread.run(AgentThread.java:185) 
+0

拋出* what * exception? – EJP 2013-03-06 19:53:27

+0

謝謝。我想編輯問題以顯示我的運行方法代碼以及它拋出的異常。 – William 2013-03-07 00:50:33

回答

1

SelectionKey.cancel()沒有充分有效,直到下select(),由於種種原因,神祕。取消後您可以嘗試撥打selectNow(),或者在重新註冊前更好。

+0

我試過了,異常消失了。謝謝! – William 2013-03-07 01:44:45

+0

對不起,麻煩你了。但是我用socketchannel讀tcp流很複雜。如何根據需要讀取絕對字節數?例如,我的bytebuffer分配512字節,一次讀512字節(假設tcp流是連續的),我只想得到200字節(其餘對於下次閱讀很重要),我該怎麼辦?非常感謝。 – William 2013-03-07 02:13:11

+0

@William分配一個200字節的ByteBuffer,或者調用'limit(200).' – EJP 2013-03-07 02:25:19