簡體   English   中英

Java NIO:serverSocketChannel接受套接字請求,客戶端收到接受,但服務器未記錄

[英]Java NIO: A serverSocketChannel accepts a socket request and client receives the acceptance but the server does not log it

我正在嘗試基於無阻塞NIO消息開發自己的通信庫。 我已經閱讀了1000篇關於它的教程和書籍,我認為最后我可以使用很少的並發連接。 但是當服務器端同時存在許多連接時,我遇到了一些問題。

我有4種私有方法的典型選擇器實現:accept,finishConnect,讀寫。 我的問題在於前兩個:Accept和finishConnect。

當客戶端打開新的套接字,並且可接受的鍵喚醒選擇器時,將執行以下代碼。

private void accept(SelectionKey key) {
    try {
        ServerSocketChannel ssc = (ServerSocketChannel) key.channel();
        SocketChannel sc = ssc.accept();
        sc.configureBlocking(false);
        LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connexion completed");
        changeInterest(sc, SelectionKey.OP_READ);
        eventManager.addEvent(new ConnectionEstablished(sc));
    } catch (Throwable e) {
        NIOException ne = new NIOException(NIOException.ErrorType.ACCEPTING_CONNECTION, e);
        eventManager.addEvent(new ErrorEvent(null, ne));
    }
}

在客戶端,我具有connect方法的這種實現,一旦服務器處理了其可接受的套接字密鑰,就會調用該方法。

private void finishConnect(SelectionKey key) {
    SocketChannel sc = (SocketChannel) key.channel();
    try {
        if (sc.finishConnect()) {
            eventManager.addEvent(new ConnectionEstablished(sc));
            LOGGER.debug("Socket " + sc.hashCode() + "-" + sc.socket().toString() + " connection finished");
        } else {
            LOGGER.debug("REFUSED " + sc + " - " + sc.socket().toString());
            refusedConnection(sc, null);
            key.cancel();
        }
    } catch (Exception e) {
        refusedConnection(sc, e);
        key.cancel();
    }
}

事實是,當我創建一些連接被接受時,客戶端將執行finishConnect消息(並且我可以看到使用所使用的端口建立的套接字連接)。 但是我在服務器端找不到這種連接接受,沒有使用這些端口的連接完成日志消息!

我懷疑ssc.accept()和日志調用之間可能會出現異常,因此我添加了一些額外的日志消息,以檢查哪個指令正在炸毀所有內容。 對於進入accept方法的所有鍵,序列均已完成。

如果我什至在日志中看不到任何錯誤消息怎么辦?

編輯:我對一次打開的套接字數進行了一些測試。 當客戶端開始運行時,服務器上只有一個openSocket:服務器套接字。 之后,它最多具有200個同時打開的套接字,並且在客戶端執行結束時,服務器將返回到1個打開的套接字。 我猜他們從來沒有被算過

到目前為止,我已經采取了一種變通方法,該方法可以監視節點上共存連接的數量,並延遲接受新的連接,直到該數量減少到給定的閾值為止。 但是,我想了解發生了什么問題。

謝謝你的幫助。

由於存在積壓隊列,因此完全可以在執行accept()之前完成大量客戶端連接。 因此,這里沒有實際要解決的問題。

但是,您是否曾經執行過accept()方法? 這是您需要調查的錯誤。

正如EJP所建議的那樣,問題在於待辦事項隊列。 我正在使用bind(SocketAddress local)方法綁定ServerSocketChannel。

當套接字請求到達JVM時,它將排隊進入待辦事項隊列,並在那里等待,直到偵聽器觸發要接受的相應密鑰的過程為止。 實際的問題在於此隊列的大小,使用bind方法,它最多可以存儲50個連接。

當連接請求達到高峰時,隊列上就會發生溢出,其中一些會丟失。 為避免發生這種情況,方法bind(SocketAddress local,int backlog)允許更改隊列的容量並增加隊列的容量。

另一方面,在非阻塞模式下工作時,客戶端節點上的選擇器不需要接受連接即可處理OP_CONNECT密鑰。 SYN-ACK TCP消息的接收將觸發選擇器中的相應密鑰。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM