Java: Complete code examples of thread-per-connection blocking IO versus NIO?

前端 未结 3 1535
长情又很酷
长情又很酷 2021-01-03 09:21

Ok, I\'m going crazy here. I have been rewriting the NIO code for my server, and running into some real headaches. The bottom line is that getting NIO \"right\" is very ha

3条回答
  •  旧时难觅i
    2021-01-03 09:57

    If you are working with NIO, I would also suggest to use a Framework. I have been working with Apache Mina and I would recommend it.

    As to the blocking IO, essentially you will need a Listener Thread that accepts incoming connections and spawns additional threads that will handle each connection. Here is an example of such a Listener code, as originally contributed to the Apache Felix Project. If you look for the complete but modified version, you can browse the source here.

    e.g.

        /*
        * Licensed to the Apache Software Foundation (ASF) under one or more
        * contributor license agreements.  See the NOTICE file distributed with
        * this work for additional information regarding copyright ownership.
        * The ASF licenses this file to You under the Apache License, Version 2.0
        * (the "License"); you may not use this file except in compliance with
        * the License.  You may obtain a copy of the License at
        *
        *      http://www.apache.org/licenses/LICENSE-2.0
        *
            * Unless required by applicable law or agreed to in writing, software
        * distributed under the License is distributed on an "AS IS" BASIS,
        * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
        * See the License for the specific language governing permissions and
        * limitations under the License.
        */
        package org.apache.felix.shell.remote;
        
        
        import java.io.IOException;
        import java.io.PrintStream;
        import java.net.ServerSocket;
        import java.net.Socket;
        import java.net.SocketException;
        
        
        /**
         * Implements a simple listener that will accept a single connection.
         * 

    * * @author Dieter Wimberger (wimpi) */ class Listener { private int m_Port; private Thread m_ListenerThread; private boolean m_Stop = false; private ServerSocket m_ServerSocket; private AtomicInteger m_UseCounter; private int m_MaxConnections; /** * Activates this listener on a listener thread (telnetconsole.Listener). */ public void activate() { //configure from system property try { m_Port = Integer.parseInt( System.getProperty( "osgi.shell.telnet.port", "6666" ) ); } catch ( NumberFormatException ex ) { Activator.getServices().error( "Listener::activate()", ex ); } try { m_MaxConnections = Integer.parseInt( System.getProperty( "osgi.shell.telnet.maxconn", "2" ) ); } catch ( NumberFormatException ex ) { Activator.getServices().error( "Listener::activate()", ex ); } m_UseCounter = new AtomicInteger( 0 ); m_ListenerThread = new Thread( new Acceptor(), "telnetconsole.Listener" ); m_ListenerThread.start(); }//activate /** * Deactivates this listener. *

    * The listener's socket will be closed, which should cause an interrupt in the * listener thread and allow for it to return. The calling thread joins the listener * thread until it returns (to ensure a clean stop). */ public void deactivate() { try { m_Stop = true; //wait for the listener thread m_ServerSocket.close(); m_ListenerThread.join(); } catch ( Exception ex ) { Activator.getServices().error( "Listener::deactivate()", ex ); } }//deactivate /** * Class that implements the listener's accept logic as a Runnable. */ private class Acceptor implements Runnable { /** * Listens constantly to a server socket and handles incoming connections. * One connection will be accepted and routed into the shell, all others will * be notified and closed. *

    * The mechanism that should allow the thread to unblock from the ServerSocket.accept() call * is currently closing the ServerSocket from another thread. When the stop flag is set, * this should cause the thread to return and stop. */ public void run() { try { /* A server socket is opened with a connectivity queue of a size specified in int floodProtection. Concurrent login handling under normal circumstances should be handled properly, but denial of service attacks via massive parallel program logins should be prevented with this. */ m_ServerSocket = new ServerSocket( m_Port, 1 ); do { try { Socket s = m_ServerSocket.accept(); if ( m_UseCounter.get() >= m_MaxConnections ) { //reject with message PrintStream out = new PrintStream( s.getOutputStream() ); out.print( INUSE_MESSAGE ); out.flush(); //close out.close(); s.close(); } else { m_UseCounter.increment(); //run on the connection thread Thread connectionThread = new Thread( new Shell( s, m_UseCounter ) ); connectionThread.start(); } } catch ( SocketException ex ) { } } while ( !m_Stop ); } catch ( IOException e ) { Activator.getServices().error( "Listener.Acceptor::activate()", e ); } }//run }//inner class Acceptor private static final String INUSE_MESSAGE = "Connection refused.\r\n" + "All possible connections are currently being used.\r\n"; }//class Listener

    You can find other examples here and here.

    Note that the advantage of NIO over the blocking model comes into play when you have more load. From a certain point on, the amount of extra work for Thread creation, management and context switching will limit your system performance.

提交回复
热议问题