简体   繁体   English

需要serverocketchannel每秒接受1000个TCP连接

[英]Need serversocketchannel accept 1000 TCP connection per second

I am using below code for connecting for my custom java nio server: 我正在使用以下代码连接我的自定义Java Nio服务器:

public static void main(String[] args) {
        try {

String value[] = { "00*********402", "00*********383",.....}
        int i = 0;

            while (i < value.length) {
                RunnableDemo temp = new RunnableDemo(value[i]);
                temp.start();
                i++;
                try {
                    Thread.sleep(1000); //REDUCING THIS TIME CAUSE PROBLEM
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

        } catch (Exception e) {

            e.printStackTrace();
        }
    }

    class RunnableDemo implements Runnable {

    private Socket socket;

    private Thread t;

    private String threadName;// equals with client number

    RunnableDemo(int phoneNumber) {
        threadName = String.valueOf(phoneNumber);
        System.err.println("Creating " + threadName);

    }

    RunnableDemo(String phoneNumber) {
        threadName = phoneNumber;
        System.err.println("Creating " + threadName);

    }

    public void run() {
        System.err.println("Running " + threadName);
        try {

            //socket = new Socket("94.232.174.97", 4664);
            socket = new Socket("192.168.20.22", 4664);
            PrintWriter testWriter = new PrintWriter(new OutputStreamWriter(
                    socket.getOutputStream()));
            testWriter.print(threadName);
            testWriter.flush();

            String incoming_message = "";
            BufferedReader bufferedIn = new BufferedReader(
                    new InputStreamReader(socket.getInputStream()));
            while (true) {
                if (bufferedIn != null) {
                    incoming_message = bufferedIn.readLine();
                    System.out.println("recived message: " +  incoming_message );
                }
            }

        } catch (Exception e) {
            System.out.println("Thread " + threadName + " interrupted.");
            e.printStackTrace();
        }
        System.out.println("Thread " + threadName + " exiting.");
    }

    public void read() {

    }

    public void start() {
        System.out.println("Starting " + threadName);
        try {
            if (t == null) {
                t = new Thread(this, threadName);
                t.start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

}

it is working fine when I create client threads each 1000 mls but when I reduce the time to 100mls (connecting 10 clients to server per second) after a few second my client threads receive below error: 当我创建每个1000毫升的客户端线程时,它工作正常,但是当我在几秒钟后将时间减少到100毫升(每秒将10个客户端连接到服务器)时,我的客户端线程收到以下错误消息:

java.net.ConnectException: Connection refused: connect
at java.net.DualStackPlainSocketImpl.connect0(Native Method)
at java.net.DualStackPlainSocketImpl.socketConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.doConnect(Unknown Source)
at java.net.AbstractPlainSocketImpl.connectToAddress(Unknown Source)
at java.net.AbstractPlainSocketImpl.connect(Unknown Source)
at java.net.PlainSocketImpl.connect(Unknown Source)
at java.net.SocksSocketImpl.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.connect(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at java.net.Socket.<init>(Unknown Source)
at RunnableDemo.run(Main.java:419)
at java.lang.Thread.run(Unknown Source)

This is the server part too: 这也是服务器部分:

public class EchoServer {

static final org.apache.log4j.Logger logger = org.apache.log4j.Logger.getLogger(Main.class);

private static final int BUFFER_SIZE = 1024;

private final static int DEFAULT_PORT = 4664;
private InetAddress hostAddress = null;

private int port;
private String ipAddress = "192.168.20.22";
private Selector selector;

// The buffer into which we'll read data when it's available
private ByteBuffer readBuffer = ByteBuffer.allocate(BUFFER_SIZE);

int timestamp = 1;

HashMap<Integer, String> connectedClients = new HashMap<Integer, String>();
HashMap<String, Integer> clientIds= new HashMap<String,Integer>();
HashMap<String, String> messageToClients = new HashMap<String, String>();


public EchoServer() {
    this(DEFAULT_PORT);
}

public EchoServer(int port)  {
    try{
        this.port = port;
        hostAddress = InetAddress.getByName(ipAddress);
        selector = initSelector();
        loop();
    }catch(Exception ex){
        logger.error("Exception Accoured:",ex);
    }
}

private Selector initSelector()  {
    try{
        Selector socketSelector = SelectorProvider.provider().openSelector();
        ServerSocketChannel serverChannel = ServerSocketChannel.open();
        serverChannel.configureBlocking(false);

        InetSocketAddress isa = new InetSocketAddress(hostAddress, port);
        serverChannel.socket().bind(isa);
        serverChannel.register(socketSelector, SelectionKey.OP_ACCEPT);

        return socketSelector;
    }catch(Exception ex){
        logger.error("Exception Accoured:",ex);
        return null;
    }
}

private void loop() {
    while (true) {
        try {

            // Do defined operations for clients
            // ------------------------------
            selector.select();
            Iterator<SelectionKey> selectedKeys = selector.selectedKeys()
                    .iterator();

            int c = 0;
            while (selectedKeys.hasNext()) {
                SelectionKey key = selectedKeys.next();
                selectedKeys.remove();

                if (!key.isValid()) {
                    logger.warn(key.hashCode() + "- is invalid");
                    continue;
                }
                // Check what event is available and deal with it
                if (key.isAcceptable()) {
                    accept(key);
                } else if (key.isReadable()) {
                    read(key);
                } else if (key.isWritable()) {
                    write(key);
                }
                c++;

            }

            logger.info(c + "  keys has been iterated");

            // Fetch List from server
            // -----------------------------------------
            try {
                ResultSet resultset = DataBase.getInstance()
                        .getQueryResult();


                while (resultset.next()) {
                    String mobileNumber = resultset.getString("MobileNo");

                    String message = resultset.getInt("IsMessage") + ","
                            + resultset.getInt("IsDeliver") + ","
                            + resultset.getInt("IsGroup") + ","
                            + resultset.getInt("IsSeen");
                    messageToClients.put(mobileNumber, message);

                }



            } catch (Exception ex) {
                //ex.printStackTrace();
                logger.error("Exception Accoured:",ex);
            }

            // Wait for 1 second
            // -----------------------------------------------
            Thread.sleep(1000);
            timestamp++;

        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }

    }
}

private void accept(SelectionKey key)  {

    try{
        // Initialize the connection ------------------------------------------
        ServerSocketChannel serverSocketChannel = (ServerSocketChannel) key
                .channel();
        SocketChannel socketChannel = serverSocketChannel.accept();
        socketChannel.configureBlocking(false);
        socketChannel.setOption(StandardSocketOptions.SO_KEEPALIVE, true);
        socketChannel.setOption(StandardSocketOptions.TCP_NODELAY, true);
        logger.info("New client accepted");

        // Fire read for reading phone number --------------------------------
        socketChannel.register(selector, SelectionKey.OP_READ);
    }catch(Exception ex){
        logger.error("Exception Accoured:",ex);
    }
}

private void read(SelectionKey key)  {

    try{
        // Initialize Socket -----------------------------------------------------
        SocketChannel socketChannel = (SocketChannel) key.channel();


        // Reading Client Number -------------------------------------------------

        readBuffer.clear();

        int numRead;
        try {
            numRead = socketChannel.read(readBuffer);
        } catch (IOException e) {
            logger.error("Forceful shutdown--->" + key.hashCode());
            key.cancel();
            return;
        }

        // read was not successful
        if (numRead == -1) {
            logger.error("Graceful shutdown ---> " + key.hashCode());
            key.cancel();
            return;
        }

        // read was successful and now we can write it to String
        readBuffer.flip();
        byte[] bytes = new byte[readBuffer.limit()];
        readBuffer.get(bytes);

        String number = new String(bytes);

        number = number.replace("\r\n", "");
        number = number.trim();

        // Update Connect Clients Status -----------------------------------------
        Integer clientId=clientIds.get(number);
        if ( clientId == null) {
            connectedClients.put(key.hashCode(), number);
            clientIds.put(number, key.hashCode());
            logger.error(number + "- (" + key.hashCode() + ") has Connected");
        }else{
            connectedClients.remove(clientId);
            connectedClients.put(key.hashCode(), number);
            clientIds.put(number, key.hashCode());
            logger.error(number + "- (" + key.hashCode() + ") REconnected");
        }

        logger.error("All clients number are:" + connectedClients.size());

        // Fire Write Operations -------------------------------------------------
        socketChannel.register(selector, SelectionKey.OP_WRITE);

    }catch(Exception ex){
        //ex.printStackTrace();
        logger.error("Exception Accoured:",ex);
    }
}

private void write(SelectionKey key)  {
    try {

        //Check channel still alive ----------------------------------------------

        String clientNumber = connectedClients.get(key.hashCode());

        if(clientNumber == null){
            key.cancel();
            logger.info("key with hash=" + key.hashCode() + " canceled");
            return;
        }

        // Get Channel -----------------------------------------------------------
        SocketChannel socketChannel = (SocketChannel) key.channel();

        // Send Message if client number have new message ------------------------

        if (messageToClients.get(clientNumber) != null) {
            logger.info(clientNumber + "-" + key.hashCode()
                            + "- Sent write message");
            String timeStamp = String.valueOf(timestamp);
            String message = messageToClients.get(clientNumber);
            ByteBuffer dummyResponse = ByteBuffer.wrap((message + "\r\n").getBytes("UTF-8"));
            socketChannel.write(dummyResponse);
            messageToClients.remove(clientNumber);
        }

        // Fire new write state --------------------------------------------------
        socketChannel.register(selector, SelectionKey.OP_WRITE);

    } catch (IOException iox) {
        logger.error("Exception Accoured:key=" + key.hashCode(),iox);
        logger.info("$$$key with hash=" + key.hashCode() + " canceled");
        key.cancel();
    } 
}

maybe there is a limit on accept connections per second on a port?! 也许端口上的每秒接受连接数有限制? I need to at least accept 1000 tcp connection per second. 我至少需要接受每秒1000个TCP连接。 can some body help? 身体可以帮忙吗?

UPDATE UPDATE

I update the amount of pending intents to 1000 by using this line of code: 通过使用以下代码行,我将待处理的意图数量更新为1000:

serverChannel.socket().bind(isa,1000);

now it receives more clients but still after a few seconds I receive connection refuse error. 现在它接收到更多的客户端,但是仍然在几秒钟后我收到connection refuse错误。

You are wasting time in your select loop doing database operations, which is rate-limiting your incoming connections. 您在执行数据库操作的select循环中浪费时间,这限制了传入连接的速率。 Don't do this. 不要这样 The only blocking operation in the select loop should be the select itself. 选择循环中唯一的阻塞操作应该是选择本身。

And you're wasting yet more time doing a one-second sleep between select calls. 而且您浪费了更多时间在选择呼叫之间进行一秒钟的睡眠。 There is no reason whatsover to do this. 没有理由要这样做。 Just get rid of it. 摆脱它。

NB When read() returns -1 you must close the channel, not just cancel the key. 注意当read()返回-1时,您必须关闭通道,而不仅仅是取消键。 Otherwise you are leaking channels. 否则,您将泄漏频道。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM