Java: code examples for blocking input-output for IO and NIO?

Okay, I'm going crazy. I rewrote the NIO code for my server and ran into some real headaches. The bottom line is that getting an NIO β€œright” is very difficult. Some people pointed me to the Rox tutorial at http://rox-xmlrpc.sourceforge.net/niotut/which seems to be on a good path, but not as complete as I would like. For example, I need to know how to close a server-side connection only after sending outgoing outgoing bytes of ByteBuffers. SocketChannel.close () is sudden and may lose data if it is done prematurely. I also need to send large packets that are larger than those read by ByteBuffer. The Rox code (or any other code I looked at) handles this. There are also many places where it seems that uncaught exceptions are not handled correctly. There are some errors in my tests, and it’s not clear how to handle them properly, given the complexity of NIO.

Anyway, when I try to solve these problems, more subtle subtleties appear, and it becomes quite complicated. Therefore, I am considering a completely different approach. Many people say that NIO is highly error prone and uselessly confusing and complex. They advocate the use of a thread-per-connection model, which uses an IO lock, where each socket connection starts in its own thread. This seems like a good idea and will reduce the bottleneck at the front end by having one selector thread for all connections (as in NIO) due to higher overhead (for threads). This feeling is repeated by posts such as http://paultyma.blogspot.com/2008/03/writing-java-multithreaded-servers.html andhttp://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html

NIO, , - . , . , , " - " , Google. - , "" - ? ? !

+3
3

NIO, Framework. Apache Mina, .

-, , , . , Apache Felix. , , .

.

    /*
    * 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.
     * <p/>
     *
     * @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.
         * <p/>
         * The listener 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 accept logic as a <tt>Runnable</tt>.
         */
        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.
             * <p/>
             * 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

.

, NIO , . , .

+1

sample/nio JDK. , .

0

, Grizzly NIO. , NIO.

0

Source: https://habr.com/ru/post/1714107/


All Articles