2012-01-20 27 views
18

Tôi muốn viết một máy chủ không đồng bộ sử dụng Java 7 và NIO 2.Tôi nên sử dụng AsynchronousServerSocketChannel để chấp nhận kết nối như thế nào?

Nhưng làm cách nào tôi nên sử dụng AsynchronousServerSocketChannel?

Ví dụ: nếu tôi bắt đầu với:

final AsynchronousServerSocketChannel server = 
    AsynchronousServerSocketChannel.open().bind(
     new InetSocketAddress(port)); 

Sau đó, khi tôi làm server.accept(), chương trình chấm dứt vì gọi đó là không đồng bộ. Và nếu tôi đặt mã đó trong một vòng lặp vô hạn, một số AcceptPendingException sẽ bị ném.

Bất kỳ đề xuất nào về cách viết một máy chủ không đồng bộ đơn giản bằng cách sử dụng AsynchronousServerSocketChannel?

Dưới đây là ví dụ của tôi đầy đủ (giống như ví dụ trong javadoc):

import java.io.IOException; 
import java.net.InetSocketAddress; 
import java.nio.channels.AsynchronousServerSocketChannel; 
import java.nio.channels.AsynchronousSocketChannel; 
import java.nio.channels.CompletionHandler; 

public class AsyncServer { 

    public static void main(String[] args) { 
     int port = 8060; 
     try { 
      final AsynchronousServerSocketChannel server = 
        AsynchronousServerSocketChannel.open().bind(
          new InetSocketAddress(port)); 

      System.out.println("Server listening on " + port); 

      server.accept("Client connection", 
        new CompletionHandler<AsynchronousSocketChannel, Object>() { 
       public void completed(AsynchronousSocketChannel ch, Object att) { 
        System.out.println("Accepted a connection"); 

        // accept the next connection 
        server.accept("Client connection", this); 

        // handle this connection 
        //TODO handle(ch); 
       } 

       public void failed(Throwable exc, Object att) { 
        System.out.println("Failed to accept connection"); 
       } 
      }); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+0

Bạn có thể sử dụng khung Netty đó là đặc biệt cho các ứng dụng client-server. Nó cũng sử dụng java NIO. Nó rất dễ dàng và nhanh chóng phát triển của máy chủ. đi qua http://netty.io/ –

+3

@Optimus: Tôi biết về netty, nhưng điều đó không liên quan đến câu hỏi này. – Jonas

Trả lời

9

Bạn đang đi đúng hướng, gọi chấp nhận() từ cuộc gọi lại hoàn thành để chấp nhận nhiều kết nối hơn sẽ hoạt động.

Cách đơn giản (nhưng xấu xí) để ngăn chặn chuỗi từ chấm dứt chỉ đơn giản là lặp cho đến khi chuỗi bị gián đoạn.

// yes, sleep() is evil, but sometimes I don't care 
while (true) { 
    Thread.sleep(1000); 
} 

Cách rõ ràng hơn là sử dụng AsynchronousChannelGroup. Ví dụ:

AsynchronousChannelGroup group = AsynchronousChannelGroup.withThreadPool(Executors 
      .newSingleThreadExecutor()); 
AsynchronousServerSocketChannel server = AsynchronousServerSocketChannel.open(group).bind(
      new InetSocketAddress(port)); 

// (insert server.accept() logic here) 

// wait until group.shutdown()/shutdownNow(), or the thread is interrupted: 
group.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS); 

Bạn có thể điều chỉnh cách xử lý luồng, xem AsynchronousChannelGroup API docs để biết thêm thông tin.

+4

'// có, ngủ() là ác, nhưng đôi khi tôi không quan tâm' Bạn nên quan tâm. –

+4

Heh. Tiếp tục nhận được downvotes về điều này, có lẽ vì các cuộc gọi sleep(), mặc dù tôi gọi nó là _ugly_ và _evil_, và sau đó chứng minh một cách đẹp hơn. Điều đó có vẻ khá là giáo điều. :-) – Soulman

3

Sử dụng đồng bộ chấp nhận là hữu ích nếu bạn có một cái gì đó khác để làm trong cùng một thread. Trong trường hợp của bạn, bạn không làm điều gì khác để tôi có thể sử dụng

while(true) { 
    AsynchronousSocketChannel socket = server.accept().get(); 
    System.out.println("Accepted " + socket); 
    socket.close(); 
} 
+0

Future.get() waits ... –

+0

@gnarly Có, nhưng chấp nhận() trả về một tương lai khác nhau mỗi lần. –

+0

Điểm của tôi là ví dụ của bạn là một máy chủ chặn, đánh bại mục đích của ['AsynchronousServerSocketChannel'] (http://docs.oracle.com/javase/7/docs/api/java/nio/channels/AsynchronousServerSocketChannel.html) . –

2

Một cách khác là để phương pháp chính của bạn chờ tín hiệu trước khi trở về. Sau đó, nếu bạn có một số loại lệnh tắt máy bên ngoài, bạn chỉ cần thông báo cho tín hiệu và chủ đề chính tắt.

private static final Object shutdownSignal = new Object(); 

public static void main(String[] args) { 

    ... 

    synchronized (shutdownSignal) { 
     try { 
      shutdownSignal.wait(); 
     } 
     catch (InterruptedException e) { 
      // handle it! 
     } 
    } 
} 
0

Sử dụng đếm ngược chốt như ví dụ sau

final AsynchronousServerSocketChannel serverChannel = AsynchronousServerSocketChannel.open(); 
    InetSocketAddress address = new InetSocketAddress(port); 
    serverChannel.bind(address); 
    final CountDownLatch latch = new CountDownLatch(1); 
    serverChannel.accept(null, new CompletionHandler<AsynchronousSocketChannel, Object>() { 
@Override 
     public void completed(final AsynchronousSocketChannel channel, Object attachment) { 
      serverChannel.accept(null, this); 
         } 

}); 
try { 
     latch.await(); 
    } catch (InterruptedException e) { 
     e.printStackTrace(); 
     Thread.currentThread().interrupt(); 
    } 
Các vấn đề liên quan