本文介绍了为什么我的非阻塞Java服务器拒绝客户端连接?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

大家好!我正在开发基于NIO的服务器,并且正在尝试使用简单的客户端程序对其进行测试.

Good day everybody! I'm developing NIO based server and I'm trying to test it with simple client programm.

在发布代码之前,我想简要地描述问题:在服务器立即完成工作的测试案例中,一切正常.但是,当我尝试添加一些现实生活中的行为(例如,服务的短暂延迟)时,出现了"java.net.ConnectException:连接被拒绝"异常.更准确地说,100个客户端线程中的一部分会收到此连接被拒绝的异常.

Before posting code I would like to briefly describe problem: in the test case where server does his job immediately everything is OK. But when I'm trying to add some real life behavior such as short delay on servicing I'm getting "java.net.ConnectException: Connection refused" exceptions. More precisely, part of 100 client threads get this connection refused exception.

我使用以下代码:

客户端

public class TCPClient implements Runnable{

private String name;

public TCPClient(String name)
{
  this.name = name;
}

public static void main(String[] args)
{

   for(int i=0;i<100;i++)
   {
        Thread t = new Thread(new TCPClient("thread # "+Integer.toString(i)));
        t.start();
   }
}

@Override
public void run()
{
   Socket socket = null;
   OutputStream out = null;
   int counter = 0;
   try
   {
        socket = new Socket();
        socket.connect(new InetSocketAddress("192.168.3.109",2345), 0); 
        out =  socket.getOutputStream();

        byte[] bytes;
        while(counter<100)
        {
            counter++;
            bytes = (name+ ", message # "+Integer.toString(counter)+System.lineSeparator()).getBytes();
            out.write(bytes); 
            out.flush();
            Thread.sleep(200);
        }
   }
   catch(Exception ex)
   {
            System.out.println(name+" "+Integer.toString(counter));
            ex.printStackTrace(new PrintStream(System.out));
            System.out.println();
   }
    finally
    {
        if(socket!=null && out!=null)
        {
            try
            {
                socket.close();
                out.close();
            }
            catch(Exception ex)
            {
                System.out.println("client close error");
            }
        }
    }
}

}

服务器

public class TCPServer  {

private Selector selector;
private boolean isRunning;
private ServerSocketChannel server;
private int counter;
private PrintWriter times;
private PrintWriter logger;
private Charset charset;
private CharsetDecoder decoder;
ByteBuffer bb;
long serviceTime,curTime;
Random random;
public TCPServer(int port)
{

    counter = 0;
    isRunning = false; 
    serviceTime = 0;
    random = new Random();
    random.setSeed(System.currentTimeMillis());
    bb =  ByteBuffer.allocate(2048);

try
{
    selector = Selector.open(); 
server = ServerSocketChannel.open(); 
server.socket().bind(new InetSocketAddress(port)); 
server.configureBlocking(false); 
server.register(selector, SelectionKey.OP_ACCEPT);


}
catch(Exception ex)
{
    System.out.println("initialization error "+ex.getMessage());

}

}


public void startServer() {
    isRunning = true;
    int acc = 0;
    boolean error = false;
    while (isRunning) {
       try 
       {


         selector.select(); 

         Set keys =  selector.selectedKeys();
         Iterator it = keys.iterator(); 
         while(it.hasNext())
         {
             SelectionKey key = (SelectionKey)it.next();

             if (key.isConnectable())
             { 
        ((SocketChannel)key.channel()).finishConnect(); 
     } 

             if (key.isAcceptable())
             { 
        //logger.println("socket accepted");
                    //logger.flush();
                    acc++;
                    System.out.println("accepted sockets count = "+acc);
                    SocketChannel client = server.accept(); 
                    client.configureBlocking(false); 
                    client.socket().setTcpNoDelay(true); 
                    client.register(selector, SelectionKey.OP_READ); 
     } 

             if (key.isReadable())
             { 

                   curTime = System.currentTimeMillis();
                   SocketChannel sc = (SocketChannel) key.channel();
                   bb.clear();
                   int x =  sc.read(bb); 

                   if(x==-1)
                   {
                       key.cancel();
                       continue;
                   }

                   counter++;

                  // Thread.sleep(2);
                   int sum=0;
                   for(int dummy=0;dummy<4000000;dummy++) // without this delay client works fine
                   {
                       sum+=random.nextInt();
                       sum%=1005;
                   }

                   serviceTime+= System.currentTimeMillis() - curTime;
                   if(counter>=10000)
                   {
                        System.out.println("recieved messages count = "+counter);
                        System.out.println("service time = "+serviceTime+" milliseconds");
                   }


     } 
         }
         keys.clear();
  } 
  catch (Exception ex) 
  {     

      System.out.println("error in recieving messages "+ex.getMessage());

  }

 }
}

public static void main(String[] args)
{

   TCPServer deviceServer = new TCPServer(2345);
   deviceServer.startServer();

}
}

问题出在for(dummy ...)循环中-这仅仅是服务延迟的模拟-解析传入消息,向DB写一些东西等所需的时间.当延迟很小时,代码可以正常工作,所有10000条消息都到达服务器(100个客户端线程X每个客户端发送100条消息),但是当虚拟循环进行3.000.000次迭代时,某些客户端线程无法连接到服务器.另一个奇怪的事情是忽略了客户端套接字的无限超时属性.我的意思是超时等于零的socket.connect(InetAddress,timeout)意味着无限超时-换句话说,服务延迟至少没有意义,我期望这样的行为.

The problem is in for(dummy...) loop - it's just simulation of service delay - time needed to parse incoming messages, write something to DB and so on. When delay is small code works fine, all of 10000 messages come to server (100 client threads X 100 messages from each client) but when dummy loop makes over 3.000.000 iterations some of client threads fail to connect to server. One more strange thing here is ignoring infinite timeout property by client socket. I mean socket.connect(InetAddress,timeout) with timeout equal to zero means infinite timeout - in other words service delay doesn't make sense at least I expect such behavior.

推荐答案

服务器套接字似乎具有允许的最大挂起连接数. 用于ServerSocket的JavaDoc 说:

It looks like the server socket has a maximum number of pending connections it will allow. The JavaDoc for ServerSocket says:

ServerSocketChannel.bind 允许配置允许的未决连接数.

ServerSocketChannel.bind allows configuration of the number of pending connections allowed.

这篇关于为什么我的非阻塞Java服务器拒绝客户端连接?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-18 05:57