[英]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.