如何使用Java NIO提供1000个并发连接

时间:2016-12-31 04:30:55

标签: java multithreading sockets nio channel

我的发件人每秒发送10000个请求(甚至更多),但我的ServerSocketChannel只能读取和处理(在线程中)8000个请求(~appx)。

虚拟代码是这样的:

public class NioReceiver {
    private int port = -1;
    private static String message = null;
    public void receive() throws IOException {
        // Get the selector
        Selector selector = Selector.open();
        // Selector is open for making connection
        // Get the server socket channel and register using selector
        ServerSocketChannel SS = ServerSocketChannel.open();
        InetSocketAddress hostAddress = new InetSocketAddress(this.port);
        SS.bind(hostAddress);
        SS.configureBlocking(false);
        int ops = SS.validOps();
        SelectionKey selectKy = SS.register(selector, ops, null);
        for (;;) {
            //Waiting for the select operation...
            int noOfKeys = selector.select();
            // The Number of selected keys are: noOfKeys
            Set selectedKeys = selector.selectedKeys();
            Iterator itr = selectedKeys.iterator();
            while (itr.hasNext()) {
                ByteBuffer buffer = ByteBuffer.allocate(1024 * 60);
                SelectionKey ky = (SelectionKey) itr.next();
                if (ky.isAcceptable()) {
                    // The new client connection is accepted
                    SocketChannel client = SS.accept();
                    client.configureBlocking(false);
                    // The new connection is added to a selector
                    client.register(selector, SelectionKey.OP_READ);
                    // The new connection is accepted from the client: client
                } else if (ky.isReadable()) {
                    // Data is read from the client
                    SocketChannel client = (SocketChannel) ky.channel();
                    String output = null;
                    buffer.clear();
                    int charRead = -1;
                    try {
                        charRead = client.read(buffer);
                    } catch (IOException e) {
                        continue;
                    }
                    if (charRead <= 0) {
                        // client closed
                        client.close();
                    } else {
                        output = new String(buffer.array());
                        message = output;
                        try {
                            new Thread(() -> {
                                processAndStore(message);
                            }).start();
                        } catch (Exception e) {
                            System.err.println("Thread exception:::" + e.getMessage());
                        }
                    } // else if of client.isConnected()
                } // else if of ky.isReadable()
                itr.remove();
            } // end of while loop
        } // end of for loop
    }

    public void processAndStore(String output) {
        String exchangeName = null;
        String dataLine = null;
        String Lines[] = output.split("\r\n");
        for (int i = 0; i < Lines.length; i++) {
            if (Lines[i].contains("Host: ")) {
                exchangeName = Lines[i].substring(6);
            }
            if (Lines[i].isEmpty()) {
                dataLine = Lines[i + 1];
            }
        }
        StringBuffer updatedLastLine = null;
        if (dataLine != null) {
            if (dataLine.contains("POST")) {
                updatedLastLine = new StringBuffer(dataLine.substring(0, dataLine.indexOf("POST")));
            } else {
                updatedLastLine = new StringBuffer(dataLine);
            }
            if (!dataLine.equals("")) {
                try {
                    if (updatedLastLine.lastIndexOf("}") != -1) {
                        updatedLastLine.replace(updatedLastLine.lastIndexOf("}"), updatedLastLine.lastIndexOf("}") + 1, ",\"name\":\"" + exchangeName
                                + "\"}");
                    } else {

                        return;
                    }
                } catch (StringIndexOutOfBoundsException e) {
                    System.out.println(updatedLastLine + "::" + dataLine);
                    System.out.println(e);
                }
                store(updatedLastLine.toString());
            }
        }
    }

    public NioReceiver(int port) {
        this.port = port;
    }
}

当我删除处理逻辑时,它能够接收更多请求,但不是全部。

如何改进我的代码以接收所有10000个传入请求。

1 个答案:

答案 0 :(得分:1)

使用线程池/消息队列而不是创建1000个线程来调用processAndStore()

启动主题昂贵

每秒启动10000个线程? 糟糕!

正如@EJP在comment中所说:

  

NIO的目的是减少所需线程的数量。你似乎没有收到消息。

除此之外,个人资料您的代码,以查看瓶颈所在,而不是猜测。

但是,无论如何,这里有一些猜测:

  1. 请勿使用StringBuffer,请使用StringBuilder 原因:请参阅Difference between StringBuilder and StringBuffer

  2. 请勿拨打lastIndexOf("}")三次 原因: lastIndexOf()是一个顺序搜索,所以相对较慢。 JVM可能会也可能不会优化多个调用,但如果性能至关重要,请不要依赖它。通过将结果分配给变量来自己动手。另请参阅Does Java optimize method calls via an interface which has a single implementor marked as final?