`
JasonShieh
  • 浏览: 520763 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

java socket非阻塞I/O 详解

阅读更多
本文转自:http://www.blogjava.net/jake1036/archive/2010/08/01/327703.html
作者:jake1036
1      非阻塞(Nonblocking)体系结构
  
         在这一部分,我将从理论的角度来解释非阻塞体系的结构及其工作原理。这部“喜剧”(当然,如果你喜欢的话也可以称做戏剧)的“人物”如下:
  ●服务器端:接收请求的应用程序。
  ●客户端:向服务器端发出请求的应用程序。
  ●套接字通道:客户端与服务器端之间的通信通道。它能识别服务器端的IP地址和端口号。数据以Buffer中元素的形式通过套接字通道传送。
  ●选择器:所有非阻塞技术的主要对象。它监视着已注册的套接字通道,并序列化服务器需要应答的请求。
  ●关键字:选择器用来对对象的请求进行排序。每个关键字代表一个单独的客户端子请求并包含识别客户端和请求类型的信息。

  2 SocketChannel 类
 
    SocketAddress rama = new SocketAddress("localhost" , 8888) ;
    利用静态工厂方法得到SocketChannel的实例。
    SocketChannel client = SocketChannel.open(rama) ;

  如果这是传统的套接字,那么就会寻求得到socket的输入或者输出流,利用通道,我们可以直接写入通道本身,
  不是写入字节数组,而是要写入ByteBuffer对象,将此对象写入 client的read 方法。

       客户端应用程序同时执行对服务器端的请求,接着选择器将其集中起来,创建关键字,然后将其发
送至服务器端。这看起来像是阻塞(Blocking)体系,因为在一定时间内只处理一个请求,但事实并非如此。
实际上,每个关键字不代表从客户端发至服务器端的整个信息流,仅仅只是一部分。我们不要忘了选择器能
分割那些被关键字标识的子请求里的数据。因此,如果有更多连续地数据发送至服务器端,那么选择器就会
创建更多的根据时间共享策略(Time-sharing policy)来进行处理的关键字。强调一下,在图一中关键字的颜色
与客户端的颜色相对应。
  

     服务器端非阻塞(Server Nonblocking)
客户端和服务器端是两个Java应用程序。套接字通道是SocketChannel类的实例,这个类允许通过网络传送数据。
它们能被Java程序员看作是一个新的套接字。SocketChannel类被定义在java.nio.channel包中。
  选择器是一个Selector类的对象。该类的每个实例均能监视更多的套接字通道,进而建立更多的连接。
当一些有意义的事发生在通道上(如客户端试图连接服务器端或进行读/写操作),选择器便会通知应用程序处理请求。
选择器会创建一个关键字,这个关键字是SelectionKey类的一个实例。每个关键字都保存着应用程序的标识及请求的类型。
其中,请求的类型可以是如下之一:

基本上,服务器端的实现是由选择器等待事件和创建关键字的无限循环组成的。根据关键字的类型,及时的执行操作。
关键字存在以下4种可能的类型。
  Acceptable: 相应的客户端要求连接。
  Connectable:服务器端接受连接。
  Readable:服务器端可读。
  Writeable:服务器端可写。



一个通用的实现非阻塞服务器的算法如下:
  create SocketChannel;
  create Selector
  associate the SocketChannel to the Selector
  for(;;) {
  waiting events from the Selector;
  event arrived; create keys;
  for each key created by Selector {
  check the type of request;
  isAcceptable:
  get the client SocketChannel;
  associate that SocketChannel to the Selector;
  record it for read/write operations
  continue;
  isReadable:
  get the client SocketChannel;
  read from the socket;
  continue;
  isWriteable:
  get the client SocketChannel;
  write on the socket;
  continue;
  }
  }


3  下面为一个实例
     (1)客户端
     
package cn.bupt.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.Channels;
import java.nio.channels.SocketChannel;
import java.nio.channels.WritableByteChannel;

import cn.bupt.constant.Default;

public class ChargenClient {

    public static int DEFAULT_PORT = 8778 ;
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
       if(args.length == 0)
       {
           System.out.println("please input the port");
           return ;
       }
       
       int port ;
       
       
       port = DEFAULT_PORT ;
       
       SocketAddress address = new InetSocketAddress(args[0] , port) ;
       try {
        SocketChannel client = SocketChannel.open(address) ;
        ByteBuffer buffer = ByteBuffer.allocate(74) ;
        WritableByteChannel out = Channels.newChannel(System.out) ;
        
        while(client.read(buffer) != -1)
        {
            buffer.flip() ;
            out.write(buffer) ;
            buffer.clear() ;
            
        }
        
        
        
        
        
        
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
       
       
        
    }

}


      
   (2) 服务器端 
        

package cn.bupt.channel;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

public class ChargenServer {
 
    public static final int DEFAULT_PORT = 8778 ;
    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int port ;
        port = DEFAULT_PORT ;
        
        byte[] rotation = new byte[95 * 2 ] ;
        for(byte i = ' ' ; i < '~' ;i++)
        {
            rotation[i - ' '] = i ;
            rotation[i + 95 - ' '] = i ;
        }
        
        ServerSocketChannel serverChannel = null  ;
        Selector selector = null;
        
        
        /**
         * 先建立服务器端的通道
         * 
         */
        
        try {
            serverChannel = ServerSocketChannel.open() ;
            ServerSocket ss = serverChannel.socket() ;
            InetSocketAddress address = new InetSocketAddress(port) ; 
            ss.bind(address) ;
            serverChannel.configureBlocking(false) ;
            selector = Selector.open() ;
            serverChannel.register(selector, SelectionKey.OP_ACCEPT) ;
            
            
        
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        
        while(true)
        {
            
            try {
                selector.select() ;
            } catch (IOException e) {
                e.printStackTrace();
            }
            
            Set readyKeys = selector.selectedKeys() ;
            Iterator iter = readyKeys.iterator() ;
            while(iter.hasNext())
            {
                SelectionKey key = (SelectionKey) iter.next() ;
                iter.remove() ;
                
                if(key.isAcceptable())
                {
                    ServerSocketChannel server = (ServerSocketChannel) key.channel() ;
                     try {
                         SocketChannel client = server.accept() ;
                         System.out.println("Accept connection from " + client) ;
                        client.configureBlocking(false) ;
                        SelectionKey key2 = client.register(selector, SelectionKey.OP_WRITE) ;
                        ByteBuffer buffer = ByteBuffer.allocate(74) ;
                        buffer.put(rotation , 0 , 72) ;
                        buffer.put((byte)'\r') ;
                        buffer.put((byte)'\n') ;
                        buffer.flip() ;
                        key2.attach(buffer) ;
                        
                        
                        
                        
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                    
                    
                    
                    
                }
                
                else
                    if(key.isWritable())
                    {
                        
                        /**
                         * 建立客户端通道
                         * 
                         */
                        SocketChannel client = (SocketChannel)key.channel() ;
                        ByteBuffer buffer = (ByteBuffer) key.attachment() ;
                        if(!buffer.hasRemaining())
                        {
                            buffer.rewind() ;
                            int first = buffer.get() ;
                            buffer.rewind() ;
                            int position = first - ' ' + 1 ;
                            buffer.put(rotation , position , 72) ;
                            buffer.put((byte) '\r') ;
                            buffer.put((byte) '\n');
                            buffer.flip() ;
                        }
                        try {
                            client.write(buffer) ;
                        } catch (IOException e) {
                            // TODO Auto-generated catch block
                            e.printStackTrace();
                        }
                    }
                    
                    
                    
                
                
                
                
                
                key.cancel() ;
                try {
                    key.channel().close() ;
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            
        
        }
        
        
        
        
        
        
        
        
        
    }

}
分享到:
评论

相关推荐

    java高手真经 光盘源码

    javanio.zip 23.NIO非阻塞通信(Socket/UDP实例、简单聊天系统) javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) java...

    Java高手真经(编程基础卷)光盘全部源码 免积分

    javanio.zip 23.NIO非阻塞通信(Socket/UDP实例、简单聊天系统) javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) java...

    Java高手真经(编程基础卷)光盘全部源码

    javanio.zip 23.NIO非阻塞通信(Socket/UDP实例、简单聊天系统) javarmi.zip 24.RMI编程(HelloWorld例、计算器实例) javacorba.zip 25.Corba编程(HelloWorld例、计算器实例) 第6部分(4个程序包) java...

    Java ServerSocket用法详解

    Java网络编程的基础知识、套接字编程、非阻塞通信、创建HTTP服务器与客户程序、数据报通信、对象的序列化与反序列化、Java反射机制、RMI框架、JDBC API、JavaMail API、MVC设计模式、安全网络通信、CORBA和Web服务

    疯狂JAVA讲义

    第1章 Java概述 1 1.1 Java语言的发展简史 2 1.2 Java的竞争对手及各自优势 4 1.2.1 C#简介和优势 4 1.2.2 Ruby简介和优势 4 1.2.3 Python的简介和优势 5 1.3 Java程序运行机制 5 1.3.1 高级语言的运行机制 6...

    java面试题,180多页,绝对良心制作,欢迎点评,涵盖各种知识点,排版优美,阅读舒心

    【基础】I/O总结 31 【基础】Java中如何实现序列化,有什么意义? 34 【WEB】session与cookie的区别与联系;session的生命周期 34 session与cookie的区别与联系 34 session的生命周期 35 【WEB】servlet 生命周期 35...

    企业网组建与设计方案.doc

    程序主要是利用socke套接字原理,实现异步非阻塞机制处理数据包,实现 数据包的收发以及丢包检测,socket套接字编程已成为网络编程的标准规范之一。 基本概念 1 TCP协议 从协议分层模型方面来讲,TCP/IP由四个层次...

Global site tag (gtag.js) - Google Analytics