Câu hỏi Làm cách nào để tránh bị chặn với Java ServerSocket?


Im làm việc trên một bộ lắng nghe socket có để lắng nghe trên 2 cổng cho 2 loại dữ liệu (cổng 80 và cổng 81). Những dữ liệu này rất giống như trong các loại hoạt động được thực hiện trên dữ liệu và chỉ khác nhau vì chúng đến các cổng khác nhau. Tôi đã đi trước và mã hóa một triển khai bằng cách sử dụng lớp ServerSocket của Java, chỉ để nhận ra sau đó phương thức accept () của lớp ServerSocket là khối và thực thi của tôi không thể đủ khả năng đó. Vì vậy, bây giờ tôi đã suy nghĩ của việc thực hiện giống nhau bằng cách sử dụng Java NIO nhưng sau khi đã đi qua một số hướng dẫn tôi nghĩ rằng tôi bối rối hơn so với cách tôi bắt đầu. Nó sẽ là tuyệt vời nếu một người nào đó ở đây có thể đi bộ tôi qua toàn bộ quá trình, ngay cả khi nó được trong mã giả hoặc jus kỹ thuật "phải làm gì tiếp theo". Đây là những gì tôi có kế hoạch để đạt được.

Nghe, như bao giờ hết trên 2 cổng bằng cách gọi 2 chủ đề tương tự. (Không chặn) Một thiết bị từ xa từ một số vị trí mạng kết nối, gửi dữ liệu và sau đó ngắt kết nối.

Tôi nghĩ rằng nếu chỉ có kiến ​​thức về cách NIO có thể được sử dụng để thiết lập một máy chủ để lắng nghe trên một cổng nói cổng 80, trên localhost, là đạt được, phần còn lại là tất cả khá dễ thực hiện.

Chúc mừng


13
2018-01-23 05:35


gốc




Các câu trả lời:


NIO được gọi khi bạn cần mở rộng tới hàng nghìn kết nối đồng thời.

Nếu không, tôi khuyên bạn nên sử dụng nhiều luồng. Đối với mỗi cổng (và tương ứng của nó) ServerSocket), tạo một chuỗi cuộc gọi accept() trong một vòng lặp. Các cuộc gọi này sẽ chặn, nhưng điều đó là ổn vì các luồng khác đang chạy, xử lý mọi tác vụ sẵn có.

Khi mới Socket được chấp nhận, tạo một luồng khác được dành riêng cho kết nối đó. Nó phụ thuộc vào ứng dụng, nhưng điển hình là luồng này sẽ đọc từ socket (một hoạt động chặn), và thực hiện thao tác được yêu cầu, ghi kết quả trở lại socket.

Kiến trúc này sẽ mở rộng đến hàng trăm kết nối trên hầu hết các nền tảng máy tính để bàn. Và mô hình lập trình khá đơn giản, miễn là mỗi kết nối là khép kín và độc lập với những người khác (điều này tránh các vấn đề tương tranh). Giới thiệu NIO sẽ cung cấp khả năng mở rộng hơn, nhưng đòi hỏi rất nhiều phức tạp.


8
2018-01-23 05:45



Không thực sự trả lời câu hỏi: người nghe socket sử dụng NIO


Dưới đây là một ví dụ nhỏ để bắt đầu với NIO.

Đó là một máy chủ nghe trên cổng 80 và 81 và in mọi thứ được nhận trên đầu ra tiêu chuẩn. Một kết nối được đóng lại sau khi nhận được một gói bắt đầu bằng CLOSE; toàn bộ máy chủ bị tắt sau khi nhận được gói bắt đầu bằng QUIT. Thiếu phần gửi và xử lý lỗi có thể tốt hơn một chút. :-)

public static void main() throws IOException {
    ByteBuffer buffer = ByteBuffer.allocate(1024);
    Selector selector = Selector.open();

    ServerSocketChannel server1 = ServerSocketChannel.open();
    server1.configureBlocking(false);
    server1.socket().bind(new InetSocketAddress(80));
    server1.register(selector, OP_ACCEPT);

    ServerSocketChannel server2 = ServerSocketChannel.open();
    server2.configureBlocking(false);
    server2.socket().bind(new InetSocketAddress(81));
    server2.register(selector, OP_ACCEPT);

    while (true) {
        selector.select();
        Iterator<SelectionKey> iter = selector.selectedKeys().iterator();
        while (iter.hasNext()) {
            SocketChannel client;
            SelectionKey key = iter.next();
            iter.remove();

            switch (key.readyOps()) {
                case OP_ACCEPT:
                    client = ((ServerSocketChannel) key.channel()).accept();
                    client.configureBlocking(false);
                    client.register(selector, OP_READ);
                    break;
                case OP_READ:
                    client = (SocketChannel) key.channel();
                    buffer.clear();
                    if (client.read(buffer) != -1) {
                        buffer.flip();
                        String line = new String(buffer.array(), buffer.position(), buffer.remaining());
                        System.out.println(line);
                        if (line.startsWith("CLOSE")) {
                            client.close();
                        } else if (line.startsWith("QUIT")) {
                            for (SelectionKey k : selector.keys()) {
                                k.cancel();
                                k.channel().close();
                            }
                            selector.close();
                            return;
                        }
                    } else {
                        key.cancel();
                    }
                    break;
                default:
                    System.out.println("unhandled " + key.readyOps());
                    break;
            }
        }
    }
}

Obs: các lĩnh vực SelectionKey (OP_ACCEPT...) được nhập tĩnh:

import static java.nio.channels.SelectionKey.*;

15
2018-01-23 18:47





Nhiều khung công tác, chẳng hạn như Apache MINA và Netty, đã được triển khai dựa trên Java NIO để tăng cường lập trình IO không chặn. Tôi đề nghị họ làm cho chương trình NIO của bạn trở thành một niềm vui, chứ không phải là một cơn ác mộng. Chúng phù hợp với vấn đề của bạn.

Ngoài ra, hãy thử sử dụng một giao thức hiệu quả cả trong kích thước tin nhắn vận chuyển và mã hóa / giải mã (serialize / deserialize) hiệu suất. Bộ đệm giao thức của Google là một giải pháp đáng tin cậy trong lĩnh vực này. Ngoài ra hãy xem Kryo và KryoNet. Chúng có thể hữu ích.


8
2018-01-23 06:30



Ngoài ra hãy xem code.google.com/p/naga - Vadzim