繁体   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