2015-01-16 2 views
0

나는 간단한 웹 가져 오기 도구가 있습니다. OP_WRITE는 항상 selector를 트리거하므로 select()는 끝나지 않습니다. Select는 항상 1을 반환하고, 채널이 작업을 끝내고 닫 혔음에도 불구하고 쓰기를 기다립니다. 어떻게 처리합니까? 또한 내 CPU가 정말 높아집니다.비 블로킹 write() 무한합니다 - 자바

여기에 코드입니다 :

public static void main(String [] args) 
{ 

try 
{ 
    String adder=""; 

    Selector selector= simpleFetcher.selector; 
    selector = Selector.open(); 

    Charset charset = Charset.forName("ISO-8859-1"); 

    try{ 

    //add to selector the host and settings 
    addHost(selector, "localhost", 80); 
    addHost(selector, "site.org", 80); 

    } catch (UnresolvedAddressException ex) {System.out.println("Address Not exist "+ex.getMessage());} 

    while(true) 
    { 

    int selectedn = selector.select(2000); 
    if (selectedn==0) 
    { 
     Set<SelectionKey> SelectorKeys = selector.keys(); 
     Iterator<SelectionKey> iterator = SelectorKeys.iterator(); 

     while(iterator.hasNext()) 
     { 
      SelectionKey k = (SelectionKey) iterator.next(); 
      SocketChannel channel = (SocketChannel) k.channel(); 

      String rHost; 
      InetAddress addr = channel.socket().getInetAddress(); 
      rHost= addr.getHostAddress(); 
      System.out.println(rHost+" is timeout"); 

     } 
     System.out.println("adder:"+adder); 
     selector.close(); 

     System.out.println("No more keys.. Exiting"); 
     return; 
    } 

    Set<SelectionKey> selectedKeys = selector.selectedKeys(); 
    Iterator<SelectionKey> iterator = selectedKeys.iterator(); 

    while(iterator.hasNext()) 
    { 
     SelectionKey key = (SelectionKey) iterator.next(); 
     iterator.remove(); 

     if (key.isValid()==false) {System.out.println("key not valid"); continue;} 


     try{ 
      if (key.isConnectable()) 
      { 

       System.out.println("Will connect right now"); 

       SocketChannel channel = (SocketChannel) key.channel(); 

       if (!channel.finishConnect()) { System.out.println("Not finished connection. continue.."); continue; } 
       if (channel.isConnectionPending()==false && channel.socket().isClosed()==true) System.out.println("CLOSED?"); 


       SelectionKey k = channel.register(key.selector(),SelectionKey.OP_READ); 
       SelectionKey k2 = channel.register(key.selector(),SelectionKey.OP_WRITE); 
       //SelectionKey k = channel.register(key.selector(),SelectionKey.OP_READ | SelectionKey.OP_WRITE); 
       k.attach(ByteBuffer.allocate(4000)); 


       System.out.println("Just Connected"); 
       continue; 
      } 
      if (key.isReadable()) 
      { 
       int readB; 
       System.out.println("Ready for reading.."); 
       SocketChannel channel = (SocketChannel) key.channel(); 
       ByteBuffer buffer = (ByteBuffer) key.attachment(); 
       CharBuffer charbuffer = buffer.asCharBuffer(); 

       if ((readB=channel.read(buffer)) !=-1) 
       { 
        System.out.println("Key accepted - reading.."); 
        int current_capacity=buffer.position(); 

        buffer.flip(); 
        CharBuffer c = charset.decode(buffer); 
        char[] arr = c.array(); 


        String data = new String(arr); 

        String[] lines = data.split("\\r\\n\\r\\n"); 
        if (lines.length>1) 
        { 
         String header = lines[0]; 
         String rest_body = lines[1]; 
         //System.out.println("Header is: "+header); 
         //System.out.println("Body is: "+rest_body); 
         adder+=header+rest_body; 
        } 
        else { adder+=new String(arr); } 


       } 
       else 
       { 
        key.channel().close(); 
        key.cancel(); 
        System.out.println("Key cancled"); 
        System.out.println(adder); 

        continue; 
       } 
       if (readB==0) System.out.println("The READ RETURNS 0"); 

        System.out.println(); 
        buffer.clear(); 

       continue; 

      } 
      if (key.isWritable()) 
      { 

       //System.out.println("Ready to write"); 

        SocketChannel channel = (SocketChannel) key.channel(); 
        String rHost; 

        Socket s = channel.socket(); 
        s.shutdownOutput(); 



        InetAddress addr = channel.socket().getInetAddress(); 
        rHost= addr.getHostAddress(); 
        //System.out.println(rHost); 

        if (s.isOutputShutdown()) continue; 

        String bytestowrite="GET/HTTP/1.1\r\nHost: "+rHost+"\r\nUser-agent: Agent 1.0 Experimental\r\nAccept: */*\r\nAccept-Language: en-US,en;q=0.5\r\nConnection: keep-alive\r\n\r\n"; 
        ByteBuffer buffer = ByteBuffer.wrap(bytestowrite.getBytes()); 

        while(buffer.hasRemaining()) channel.write(buffer); 
        key.cancel(); 
       continue; 
      } 


     } catch (IOException ex) { 
      System.out.println("EXCEPTION: "+ex.getMessage()); 
      key.cancel(); 
      try { key.channel().close();} 
      catch (IOException cex) {}; 
     } 

     System.out.println("End of iterator loop"); 
    } 
    } 
}catch (IOException ex) {System.out.println("Timeout");} 



} 

답변

2

소켓 채널은, 거의 항상 소켓 전송 버퍼에 사용 가능한 공간이 거의 항상 존재 의미 쓸 수 있습니다. 보낸 사람이 수신자를 앞지르면 그만 사실입니다.

이미 버퍼 가득 조건이 발생하지 않은 경우, 즉 write()가 0을 반환하고 후속 쓰기가 성공하면 OP_WRITE를 검색해야하는 경우가 아니면 OP_WRITE 채널을 등록하는 것이 맞지 않습니다.

+0

EJP 다시 도움 주셔서 감사합니다! 그런 문제를 피하는 법을 아십니까? 예를 들어 필자가 글쓰기를 멈출 필요가있는 것을 쓴다면? key.cancel()이 작업을 수행합니까? (OP_READ | OP_WRITE의 키를 등록했습니다) –

+1

방금 ​​대답했습니다. * 내가 설명한 상황에서 OP_WRITE *를 제외하고 * 등록하지 마십시오. 올바르지 않습니다. 위 참조. – EJP