2013-03-06 4 views
0

클라이언트 측의 서버에서 TCP 스트림을 수신하려면 SocketChannel을 사용합니다. 예를 들어 :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() 방법을 사용할 수 있습니다. 내가 서버 측에서 TCP 스트림을 수신하기 위해 (내가 읽은 스트림 라인 싶어)의 InputStream을 사용하고 싶습니다 고려 콘크리트 핸들

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 
       ... 
      } 
     } 
     } 
    } 
} 

는 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(); 
} 
     ......① 

확인을 한 time.In 순서가 선택기를 사용하여 계속하는 지금은 TCP 스트림을 읽은 나는 false로 블록 모드 채널을 설정해야합니다.

channel.configureBlocking(false); 

질문은 채널과 선택자를 결합한 키가 취소되었습니다. mychannel을 다시 등록하고 싶습니다. 어떻게해야합니까? ①에 mychannel.register(selector, SelectionKey.OP_READ)을 다시 사용하면 Exception가 발생합니다.

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

+0

감사합니다. 내 실행 메소드 코드를 표시하고 예외가 발생하는 예외를 편집하고 싶습니다. – William

답변

1

SelectionKey.cancel() 다양한 비밀의 이유로, 다음 select()까지 전체 적용되지 않습니다 : 그것은 던졌습니다 예외는

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(); 
} 

다음과 같이

내 run() 메소드 코드는 . 취소 후 selectNow()으로 전화를 시도하거나 재 등록 직전에 전화를 걸어보십시오.

+0

노력했지만 예외가 없어졌습니다. 감사합니다! – William

+0

당신을 괴롭히지 않아서 죄송합니다.하지만 나는 원하는대로 절대 바이트 수를 읽을 수 있습니까? 예를 들어, 제 바이트 버퍼는 512 바이트를 할당하고 한 번에 512 바이트를 읽습니다 (TCP 스트림을 가정 함). 연속적입니다.) 200 바이트를 얻고 싶습니다. 나머지는 다음 독서에서 중요합니다. 어떻게해야합니까? 정말 고마워요. – William

+0

@William 200 바이트의 ByteBuffer를 할당하거나 그렇지 않으면 limit (200)을 호출하십시오. – EJP