Java:完整的每个连接线程阻塞IO与NIO的代码示例? [英] Java: Complete code examples of thread-per-connection blocking IO versus NIO?

查看:111
本文介绍了Java:完整的每个连接线程阻塞IO与NIO的代码示例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我在这里疯了。我一直在为我的服务器重写NIO代码,并遇到了一些真正的麻烦。最重要的是,让NIO正确是非常困难的。有些人在 http://rox-xmlrpc.sourceforge.net/niotut/向我指出了Rox教程。 ,这似乎是一条很好的道路,但并不像我想的那样完整。例如,我需要知道如何在已经发送排队的传出ByteBuffers之后关闭服务器端的连接。 SocketChannel.close()是突然的,如果提前完成,可能会丢失数据。我还需要发送大于读取ByteBuffer的大数据包。 Rox代码(我看过的任何其他代码)都没有解决这个问题。还有许多地方似乎未被捕获的异常未得到妥善处理。在我的测试中有一些错误,并且由于NIO的复杂性,如何正确处理它们并不清楚。

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 hard. Some people pointed me to the Rox tutorial at http://rox-xmlrpc.sourceforge.net/niotut/, which seems to be on a good path, but is not as complete as I would like. For example, I need to know how to close a connection on the server side only after queued outgoing ByteBuffers have been sent. SocketChannel.close() is abrupt and can lose data if done prematurely. I also need to send large packets that are larger than the read ByteBuffer. The Rox code (nor any other code I've looked at) deals with this. There are also many places where it seems uncaught exceptions are not properly handled. In my tests there are some errors and it's not clear how to handle them properly given the complexity of NIO.

无论如何,当我试图解决这些问题时,更多的狡猾的微妙之处出现了,而且变得非常复杂。所以我正在考虑一种完全不同的方法。很多人都说NIO非常容易出错,而且不必要地混淆和复杂。他们提倡使用每线程连接模型,该模型使用阻塞IO,其中每个套接字连接在其自己的线程上运行。这似乎是一个好主意,并且通过为所有连接(如在NIO中)设置一个选择器线程来减少前端的瓶颈,代价是更高的开销(对于线程)。这种情绪与 http:// paultyma等帖子相呼应。 blogspot.com/2008/03/writing-java-multithreaded-servers.html http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html

Anyhow, as I try to solve these problems, more of the tricky subtleties show up, and it's getting quite complex. So I'm considering an entirely different approach. Many people are saying that NIO is highly error-prone and needlessly confusing and complex. They advocate using a "thread-per-connection" model that uses blocking IO where each socket connection is run on its own thread. This seems like a good idea, and would reduce the bottleneck on the front end by having one selector thread for all connections (as in NIO), at the expense of higher overhead (for the threads). This sentiment is echoed by posts such as http://paultyma.blogspot.com/2008/03/writing-java-multithreaded-servers.html and http://mailinator.blogspot.com/2008/02/kill-myth-please-nio-is-not-faster-than.html

与NIO相比,代码应该简单,但我真的想要一些示例代码来查看。我似乎找不到任何东西。问题是,我不认为这种每个连接的线程阻塞I / O策略有一个更好的名称,我实际上可以获得良好的Google结果。任何人都可以链接我一些教程或简单的例子,以解释使用这种较旧的I / O方法并使用线程池扩展它?还是有其他任何智慧的话?非常感谢!

The code should be simple compared to NIO, but I really want some example code to look at. I can't seem to find anything. The problem is that I don't think this "thread-per-connection blocking I/O" strategy has a better name that I can actually get good Google results for. Can anyone link me to some tutorials or simple examples to explain using this "older" method of I/O and scaling it up using a thread pool? Or have any other words of wisdom? Thanks very much!

推荐答案

如果您正在使用NIO,我还建议您使用框架。我一直在使用 Apache Mina ,我会推荐它。

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.

对于阻塞IO,基本上你需要一个监听器线程来接受传入的连接并产生将处理每个连接的其他线程。下面是一个这样的Listener代码的示例,最初是为Apache Felix Project提供的。
如果你找到完整但修改过的版本,你可以在这里浏览源

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.

例如

    /*
    * 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'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 <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

你可以找到其他的例子这里这里

You can find other examples here and here.

请注意,当您有更多负载时,NIO优于阻止模型的优势就会发挥作用。从某一点来看,线程创建,管理和上下文切换的额外工作量将限制您的系统性能。

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.

这篇关于Java:完整的每个连接线程阻塞IO与NIO的代码示例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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