【问题标题】:NIO client giving exception : java.net.ConnectException: Connection refused: no further informationNIO 客户端给出异常:java.net.ConnectException:连接被拒绝:没有更多信息
【发布时间】:2020-05-13 02:21:49
【问题描述】:

我修改了可用的示例代码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 - 如果此通道未连接且未启动连接操作。

ClosedChannelException - 如果此频道已关闭。

AsynchronousCloseException - 如果另一个线程在连接操作正在进行时关闭此通道。

ClosedByInterruptException - 如果另一个线程在连接操作正在进行时中断当前线程,从而关闭通道并设置当前线程的中断状态。

IOException - 如果发生其他一些 I/O 错误。

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

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

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

【问题讨论】:

  • 你用的是windows还是linux?

标签: java nio


【解决方案1】:

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");
        }
    }*/

摆脱这种垃圾。在非阻塞模式下自旋循环是不合适的。甚至不要让它像 cmets 一样闲置:稍后可能会有一些白痴来玩把它放回去。

    channel.configureBlocking(false);

通道已经处于非阻塞模式。否则你不会在这里。删除。

    channel.register(selector, SelectionKey.OP_WRITE);

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

睡在网络代码中实际上是在浪费时间。解决不了任何问题。

您假设write() 完全成功,而您忽略了它返回的计数。

您使用的参考质量很差:

  • 关于write() 的备注同上。
  • flip() 不像“重置”。
  • 取消按键会关闭频道。
  • 您不必清除一个全新的ByteBuffer,,但无论如何为每次读取分配一个ByteBuffer 是不好的做法。
  • ServerSocketChannel.accept()可以回null.
  • 读取后显示String的代码不正确。
  • 当密钥有附件时,无需使用Map
  • 当 NIO 无论如何都可中断时,无需继续测试 Thread.interrupted()
  • 没有必要因为一个频道上有一个IOException 而关闭所有内容。

试着找到更好的东西。

【讨论】:

  • 感谢您解释许多事情。服务器肯定已启动并正在侦听。我不知道侦听队列如何填满。请也查看我的编辑。
  • 如果您的服务器不能尽快接受连接,则侦听队列可能会填满。这听起来像是问题:当 Windows 积压队列填满时,它开始拒绝连接。
  • 1)你能告诉我最常见的积压队列大小是多少。我读到非服务器 Windows 机器是 5,服务器机器是 200。我正确吗? 2)我在创建新客户端时让线程睡眠,即 100 个客户端,然后 5 秒睡眠,然后 100 个客户端。它适用于大约 4000 个线程。但是当我创建 10,000 个线程时,大约有 8500 个幸存下来。休息连接被拒绝。你能说出可能是什么原因吗?我认为积压队列不可能是最初处理它们的原因?
  • @cruxioneffux (1) 50 或系统默认值。 (2) 当您将睡眠放入时,积压队列并没有比您的接受循环提前太多。当您将它们取出时,您的接受循环无法跟上,因此积压队列已填满。看看你是否可以加快你的接受循环:例如,将线程初始化移到 run() 方法中。
【解决方案2】:

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

【讨论】:

  • 它将来自SocketChannel.finishConnect().
【解决方案3】:

尝试使用命令进行 Telnet -

telnet [host IP] [port] 

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多