簡體   English   中英

NIO 客戶端給出異常:java.net.ConnectException:連接被拒絕:沒有更多信息

[英]NIO client giving exception : java.net.ConnectException: Connection refused: no further information

我修改了此處為 Client 和 Server My client 提供的示例代碼:

public class Client {

public static void main(String[] args) {

    int n=10000;
    SocketTest [] st= new SocketTest[n];
    for(int i=0;i<n;i++)
        st[i]= new SocketTest("hi");

    for(int i=0;i<n;i++)
        new Thread(st[i]).start();
   }
}
class SocketTest implements Runnable {

    private String message = "";
    private Selector selector;
    private int i;


    public SocketTest(String message){
        this.message = message;
    }

    @Override
    public void run() {
        SocketChannel channel;
        try {
            selector = Selector.open();
            channel = SocketChannel.open();
            channel.configureBlocking(false);

            channel.register(selector, SelectionKey.OP_CONNECT);
            channel.connect(new InetSocketAddress("127.0.0.1", 8511));


            while (!Thread.currentThread().isInterrupted()){

                selector.select();

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

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

                    if (!key.isValid()) continue;

                    if (key.isConnectable()){                           
                            connect(key);
                        System.out.println("I am connected to the server");
                    }   
                    if (key.isWritable()){
                        write(key);
                    }
                    if (key.isReadable()){
                        read(key);
                    }
                }   
            }
        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        } finally {
            close();
        }
    }

    private void close(){
        try {
            selector.close();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private void read (SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        ByteBuffer readBuffer = ByteBuffer.allocate(1000);
        readBuffer.clear();
        int length;
        try{
        length = channel.read(readBuffer);

        } catch (IOException e){
            System.out.println("Reading problem, closing connection");
            key.cancel();
            channel.close();
            return;
        }
        if (length == -1){
            System.out.println("Nothing was read from server");
            channel.close();
            key.cancel();
            return;
        }
        readBuffer.flip();
        byte[] buff = new byte[1024];
        readBuffer.get(buff, 0, length);
        //length=buff.length;

        String fromserver = new String(buff,0,length,"UTF-8");
        length = fromserver.length();
        System.out.println("Server said: "+fromserver);

        key.interestOps(SelectionKey.OP_WRITE);
    }

    private void write(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        i++;
        message = "location now "+i;
        try{
            Thread.sleep(5000);

        }
        catch(InterruptedException ie)
        {
            System.out.println(""+ie);
        }
        channel.write(ByteBuffer.wrap(message.getBytes()));

        // lets get ready to read.
        key.interestOps(SelectionKey.OP_READ);
    }

    private void connect(SelectionKey key) throws IOException {
        SocketChannel channel = (SocketChannel) key.channel();
        try
        {
            if(!channel.finishConnect())
                System.out.println("* Here *");
        }
        catch(ConnectException e)
        {
            System.out.println("BP 1");
            e.printStackTrace();

            //channel.close();
            //key.cancel();
            //return;
        }
        /*if (channel.isConnectionPending()){
            while(!channel.ffinishConnect()){
                System.out.println("not connected");
            }
        }*/

        channel.configureBlocking(false);
        channel.register(selector, SelectionKey.OP_WRITE);
    }
}

我通過創建多個線程在同一台機器上創建多個客戶端。 線程數由 n 值決定。 當我運行很少的客戶端時,我沒有遇到任何問題,但是一旦我使用 n 為 500 即 500 個客戶端線程運行,某些線程運行正常,但在某些線程中我遇到了這個: java.net.ConnectException: Connection refused: no further information at sun.nio.ch.SocketChannelImpl.checkConnect(Native Method) at sun.nio.ch.SocketChannelImpl.finishConnect(Unknown Source) at SocketTest.connect(Client.java:143) at SocketTest.run(Client.java:61)

第 143 行是: if(!channel.finishConnect())所以當我閱讀這個方法的文檔時,它說它拋出:

NoConnectionPendingException - 如果此通道未連接且未啟動連接操作。

ClosedChannelException - 如果此通道已關閉。

AsynchronousCloseException - 如果在連接操作正在進行時另一個線程關閉此通道。

ClosedByInterruptException - 如果在連接操作正在進行時另一個線程中斷當前線程,從而關閉通道並設置當前線程的中斷狀態。

IOException - 如果發生其他一些 I/O 錯誤。

但異常是 ConnectException。 我試圖抓住它,但它沒有進入 catch 塊。

任何幫助將不勝感激。 謝謝。 編輯:我在 Windows 上工作。 我嘗試更改 n 的值,看看創建了多少個客戶端以及有多少個導致異常,這些是結果(我知道在每次測試后等待更多時間將允許更多打開的套接字,因為在 TIME_WAIT 之后每個測試 scokets 將被釋放):

n clients connected(by keeping a count at server) 1000 522 2000 568 3000 626 4000 600 (maybe I gave less time before successive runs) 5000 1345 6000 1389我的問題是如何只有這么多客戶端才能連接。 任何人都可以建議更好的參考來閱讀客戶端服務器 NIO。

編輯 2

正如 EJP 在他的評論中提到的,窗口積壓隊列已滿。 我修改了客戶端代碼以生成 100 個線程,然后休眠 5 秒,這樣隊列上的負載並不多,並且大部分連接都成功了(但是,在建立 10,000 個連接時,仍有一些連接失敗)。

ConnectException: connection refused意味着沒有任何東西在您嘗試連接的 IP:port 上偵聽,或者在服務器的偵聽積壓隊列已滿的某些平台上。 如果它被拋出並且你正確地抓住它,你肯定會抓住它。 您必須擴展實際發生的情況以及實際捕獲代碼的樣子以獲得進一步幫助。

但是,您還有許多其他問題:

private void connect(SelectionKey key) throws IOException {
    SocketChannel channel = (SocketChannel) key.channel();
    try
    {
        if(!channel.finishConnect())
            System.out.println("* Here *");

此時,如果finishConnect()返回false,則應返回。 應該告吹並重新注冊為通道OP_WRITE. 連接仍在等待中。 打印"* Here *"也很無用。 嘗試打印一些有意義的東西。

    }
    catch(ConnectException e)
    {
        System.out.println("BP 1");
        e.printStackTrace();

        //channel.close();

此時您當然應該關閉通道。 它對人或獸沒有進一步的用處。

        //key.cancel();

關閉通道會取消該鍵。 在遇到的地方刪除。

        //return;

如上所述,此時您當然應該返回。

    }
    /*if (channel.isConnectionPending()){
        while(!channel.ffinishConnect()){
            System.out.println("not connected");
        }
    }*/

擺脫這個渣滓。 在非阻塞模式下自旋循環是不合適的。 甚至不要把它作為評論放在一邊:一些白痴可能會在稍后出現並把它放回去。

    channel.configureBlocking(false);

通道已經處於非阻塞模式。 否則你不會在這里。 消除。

    channel.register(selector, SelectionKey.OP_WRITE);

另一種方法是key.interestOps(SelectionKey.OP_WRITE);

沉睡在網絡代碼中實際上是在浪費時間。 它不解決任何問題。

您假設write()完全成功,並且您忽略了它返回的計數。

您使用的是質量相當差的參考:

  • 關於write()相同評論適用於上述內容。
  • flip()不是“像重置”。
  • 取消一個鍵會關閉通道。
  • 您不必清除全新的ByteBuffer,但在任何情況下,每次讀取分配一個ByteBuffer都是不好的做法。
  • ServerSocketChannel.accept()可以返回null.
  • 讀取后顯示字符串的代碼不正確。
  • 當鍵有附件時,不需要使用Map
  • 無論如何,當 NIO 可中斷時,無需繼續測試Thread.interrupted()
  • 沒有必要僅僅因為一個通道上的一個IOException就關閉所有東西。

嘗試找到更好的東西。

我相信您在 500 個線程中獲得的ConnectException不是來自SocketTest.connect() 它可能來自任何其他 IO 方法。

為了快速修復(並說服自己),您可以像這樣在主try-catch塊中顯式捕獲ConnectException

try {
    // connect, write, and read ...
} catch (ConnectException ce) {  // <-- catch the more specific Exception first
    System.out.println("You caught a ConnectException.");
} catch (IOException e1) {       // <-- you originally only caught this
    // TODO Auto-generated catch block
    e1.printStackTrace();
} finally {

至於為什么會發生這種情況,我可以告訴您,我目前正在增加數百個線程來測試 SOAP 服務。 我的連接也到處都是斷開的,所以對於如此大量的並發線程,這可能是意料之中的。

嘗試使用命令執行 Telnet -

telnet [host IP] [port] 

問題可能與防火牆阻止端口有關。

暫無
暫無

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

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