使用Java NIO进行10000并发连接 [英] 10000 concurrent connection using Java NIO

查看:74
本文介绍了使用Java NIO进行10000并发连接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我写了一个服务器(类似于一个这里)和< a href =https://stackoverflow.com/questions/30473163/nio-client-giving-exception-java-net-connectexception-connection-refused-no>客户端代码使用Java nio。

I wrote a Server(similar to one here) and Client code using Java nio.

我正在努力实现尽可能多的连接。
从之前的建议开始,我放慢了客户端创建过程的速度,让操作系统(Windows 8)有足够的时间处理请求。

I am trying to achieve as many connections as possible. From previous suggestions I slowed down the process of Client creation giving OS(Windows 8) enough time to handle the requests.

我在不同的客户端代码上运行机器,以便服务器具有所有可用的运行空间。

I ran the Client code on different machine so that Server has all available space for running.

当我尝试创建10,000个连接时,大约8500个连接并且拒绝连接和拒绝连接客户端(客户端代码中的线程)发生的更多,稍后创建(对于客户端代码中的循环)。

When I try to create 10,000 connections around 8500 are getting connected and rest are refused for connection and the refusal of connection for clients(threads in client code) happens more which are created later (for loop in Client code ).

我的CPU和内存使用率非常高。我想看看大多数(占总CPU消耗的48%)由select方法消耗(主要由gui事件休息)。是因为这么多客户?我也看到有些人在JRE7中抱怨这个错误,并建议使用JRE6。

My CPU and Memory usage go drastically high.I profiled to see most(48% of total CPU consumption) is consumed by select method (rest mostly by gui events) . Is it due to so many clients ? also I saw some people complaining about this bug in JRE7 and suggesting to use JRE6 .

javaw.exe的内存使用率为2000+ MB 进程。(我注意到有一个进程使用了​​低内存但CPU使用率很高)。当所有8500个左右的客户端连接时,总体使用率约为98%。系统也多次绞死但继续服务。我看到非页面池内存使用量在这个过程中从178 MB增加到310 MB(最大限制是多少?)。是不是因为当我们写入套接字时非页面使用汇集内存?

Memory Usage are 2000+ MB for javaw.exe processes.(I noticed 1 process which was using low memory but had major CPU usage ).Overall usage we around 98% when all 8500 or so clients were connected. The system hanged too for many times but continued to service.I saw Non-page pooled memory usage increased during the process from 178 MB to 310 MB (what is the max limit ?).Is it because when we write to sockets Non-page pooled memory is used ?

任何人都可以告诉我可能会遇到哪些限制因此10,000次成功连接是不可能的?
(每个进程限制的套接字?)(非分页内存?)(Backlog Queue再次?)
调整可能允许限制被推送? (Windows机器)

Can anybody please tell which limits I might be hitting so the 10,000 successful connections are not possible ? (Socket per process limit ?)(Non-paged memory ?)(Backlog Queue again ?) Tweaks that might be able to allow limits to be pushed ? (Windows machine)

我在4GB系统上使用Windows 8.

I am using Windows 8 on a 4GB system.

`

public class Server implements Runnable  {

public final static String ADDRESS = "192.168.2.14";

public final static int PORT = 8511;

public final static long TIMEOUT = 10000;

public int clients;

ByteBuffer readBuffer = ByteBuffer.allocate(1024);

private ServerSocketChannel serverChannel;

private Selector selector;

private Map<SocketChannel,byte[]> dataTracking = new HashMap<SocketChannel, byte[]>();

public Server(){
    init();
}

private void init(){
    System.out.println("initializing server");

    if (selector != null) return;
    if (serverChannel != null) return;

    try {
        selector = Selector.open();
        serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);
        serverChannel.socket().bind(new InetSocketAddress(ADDRESS, PORT));
        serverChannel.register(selector, SelectionKey.OP_ACCEPT);
    } catch (IOException e) {
        e.printStackTrace();
    }
}

@Override
public void run() {
    System.out.println("Now accepting connections...");
    try{
        while (!Thread.currentThread().isInterrupted()){

            int ready = selector.select();
            if(ready==0)
                continue;
            Iterator<SelectionKey> keys = selector.selectedKeys().iterator();

            while (keys.hasNext()){
                SelectionKey key = keys.next();
                keys.remove();
                if (!key.isValid()){
                    continue;
                }

                if (key.isAcceptable()){
                    System.out.println("Accepting connection");
                    accept(key);
                }

                if (key.isWritable()){
                    System.out.println("Writing...");
                    write(key);
                }

                if (key.isReadable()){
                    System.out.println("Reading connection");
                    read(key);
                }
            }
        }
    } catch (IOException e){
        e.printStackTrace();
    } finally{
        closeConnection();
    }

}

private void write(SelectionKey key) throws IOException{

    SocketChannel channel = (SocketChannel) key.channel();
    byte[] data = dataTracking.get(channel);
    dataTracking.remove(channel);
    **int count = channel.write(ByteBuffer.wrap(data));
    if(count == 0)
    {
        key.interestOps(SelectionKey.OP_WRITE);
        return;
    }
    else if(count > 0)
    {
        key.interestOps(0);
        key.interestOps(SelectionKey.OP_READ);  
    }** 
}

private void closeConnection(){

    System.out.println("Closing server down");
    if (selector != null){
        try {
            selector.close();
            serverChannel.socket().close();
            serverChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

private void accept(SelectionKey key) throws IOException{
    ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key.channel();
    SocketChannel socketChannel = serverSocketChannel.accept();
    if(socketChannel == null)
    {
        throw new IOException();
    }
    socketChannel.configureBlocking(false);
     clients++;
    **//socketChannel.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);
    SelectionKey skey = socketChannel.register(selector, SelectionKey.OP_READ);**

    byte[] hello = new String("Hello from server").getBytes();
    dataTracking.put(socketChannel, hello);
}

private void read(SelectionKey key) throws IOException{
    SocketChannel channel = (SocketChannel) key.channel();
    readBuffer.clear();
    int length;
    try {
        length = channel.read(readBuffer);
    } catch (IOException e) {
        System.out.println("Reading problem, closing connection");
        System.out.println("No of clients :"+clients);
        key.cancel();
        channel.close();
        return;
    }
    if (length == -1){
        System.out.println("Nothing was there to be read, closing connection");
        channel.close();
        key.cancel();
        return;
    }

    readBuffer.flip();
    byte[] data = new byte[1000];
    readBuffer.get(data, 0, length);
    String fromclient = new String(data,0,length,"UTF-8");
    System.out.println("Received: "+fromclient);
    String dat = fromclient+channel.getRemoteAddress();
    data= dat.getBytes();
    echo(key,data);
}

private void echo(SelectionKey key, byte[] data) throws IOException{
    SocketChannel socketChannel = (SocketChannel) key.channel();
    dataTracking.put(socketChannel, data);
    **//key.interestOps(SelectionKey.OP_WRITE);
    try
    {
        write(key);
    }
    catch(IOException e)
    {
        System.out.println("Problem in echo"+e);
        e.printStackTrace();
    }
}
public static void main(String [] args)
{
    Thread serv = new Thread(new Server());
    serv.start();
}

}

推荐答案

socketChannel.register(selector, SelectionKey.OP_WRITE|SelectionKey.OP_READ);

这是不正确的用法。您的选择器将旋转,因为 OP_WRITE 几乎总是准备好,除非在套接字发送缓冲区已满的极少数情况下。这就是为什么你没有尽可能快地处理 OP_ACCEPT 。当你没有什么可写的时候,你正在忙着处理 OP_WRITE

This is incorrect usage. Your selector will spin, as OP_WRITE is almost always ready, except at the rare times when the socket send buffer is full. This is why you're not processing OP_ACCEPT as fast as you could. You're busy processing OP_WRITE at times when you have nothing to write.

使用<$的正确方法c $ c> OP_WRITE 如下:


  • 注册新接受的频道OP_READ

  • 如果您有要写入频道的内容,请将其写入

  • 如果该写入返回零,注册 OP_WRITE 的频道,保存你试图写的 ByteBuffer ,并返回到选择循环

  • OP_WRITE 在频道上触发时,使用相同的缓冲区调用 write() / li>
  • 如果写入成功且未返回零,则再次注册 OP_READ ,或者至少删除 OP_WRITE 来自 interestOps

  • Register a newly accepted channel for OP_READ only
  • When you have something to write to the channel, just write it
  • If that write returns zero, register the channel for OP_WRITE, save the ByteBuffer you were trying to write, and return to the select loop
  • When OP_WRITE fires on the channel, call write() with the same buffer
  • if that write succeeds and doesn't return zero, register OP_READ again, or at least remove OP_WRITE from the interestOps.

NB关闭频道取消它的钥匙。您不需要取消。

NB Closing a channel cancels its key. You don't need the cancel.

这篇关于使用Java NIO进行10000并发连接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆