NIO 客户端给出异常:java.net.ConnectException:连接被拒绝:没有更多信息

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

我修改了可用的示例代码here for Client and Server 我的客户:

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 - If this channel is not connected and a connection operation has not been initiated.

ClosedChannelException - If this channel is closed.

AsynchronousCloseException - If another thread closes this channel while the connect operation is in progress.

ClosedByInterruptException - If another thread interrupts the current thread while the connect operation is in progress, thereby closing the channel and setting the current thread's interrupt status.

IOException - If some other I/O error occurs.

但是异常是ConnectException。 我试着抓住它,但它没有进入 catch 块。

如有任何帮助,我们将不胜感激。谢谢。 编辑: 我正在研究 windows。 我尝试更改 n 的值,查看创建了多少个客户端以及多少个导致的异常,这些是结果(我知道每次测试后等待更多时间将允许更多打开的套接字,因为每个测试 scokets 将在 [=37 之后释放=]):

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 在他的评论中提到的,window 积压队列已满。 我修改了客户端代码以生成 100 个线程,然后休眠 5 秒,这样 Queue 上没有太多负载并且大部分连接都成功(但是当建立 10,000 个连接时仍然有些连接失败)。

我相信您使用 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 服务。我也到处都是连接中断,所以对于如此大量的并发线程来说,这可能是预料之中的。

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() returned false,你应该return。您应该 而不是 失败并重新注册 OP_WRITE. 的频道 连接仍处于挂起状态。打印 "* Here *" 也是徒劳的。尝试打印一些有意义的东西。

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

        //channel.close();

此时您当然应该关闭频道。人畜无用

        //key.cancel();

关闭频道会取消密钥。删除任何遇到的地方。

        //return;

如上,此时你当然应该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() 完全成功,而忽略了 returns 的计数。

您使用的参考质量相当差:

  • 关于 write() 的相同评论同样适用。
  • flip() 不是 'like a reset'.
  • 取消按键关闭频道。
  • 您不必清除全新的 ByteBuffer,,但在任何情况下,每次读取分配 ByteBuffer 都是不好的做法。
  • ServerSocketChannel.accept()可以returnnull.
  • 读取后显示String的代码不正确。
  • 当密钥有附件时,不需要使用 Map
  • 当 NIO 可中断时,无需继续测试 Thread.interrupted()
  • 没有必要因为一个IOException一个频道就关闭所有东西。

尝试找到更好的东西。

尝试使用命令进行 Telnet -

telnet [host IP] [port] 

问题可能与防火墙阻止端口有关。