文档章节

NIO服务器

蜀山下的鱼
 蜀山下的鱼
发布于 2015/04/29 00:38
字数 955
阅读 19
收藏 0

 

其实这个是我自己对NIO做服务器时的一点见解,要是不太对,望赐教,这个图和数据通信的时分复用图差不多吧!

 

 

package org.com.mayi;

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.LinkedList;
import java.util.Set;

public class SelectorServer 
{
    private static int DEFAULT_SERVERPORT = 6018;//默认端口
    private static int DEFAULT_BUFFERSIZE = 1024;//默认缓冲区大小为1024字节
    private ServerSocketChannel channel;
    private LinkedList<SocketChannel> clients;
    private Selector readSelector;
    private ByteBuffer buffer;//字节缓冲区
    private int port;
    
    //构造函数,初始化数据
    public SelectorServer(int port) throws IOException
    {
        this.port = port;
        this.clients = new LinkedList<SocketChannel>();
        this.channel = null;
        this.readSelector = Selector.open();//打开选择器
        this.buffer = ByteBuffer.allocate(DEFAULT_BUFFERSIZE);
    }
    
    
     // 服务器程序在服务循环中调用sericeClients()方法为已接受的客户服务
    public void serviceClients()throws IOException
    {
        Set<?> keys;
        Iterator<?> it;
        SelectionKey key;
        SocketChannel client;
        // 在readSelector上调用select(long timeout)方法,
        //timeout - 如果为正,则在等待某个通道准备就绪时最多阻塞 timeout 毫秒;
        //如果为零,则无限期地阻塞;必须为非负数 
        if(readSelector.select(1) > 0)
        {
            keys = readSelector.selectedKeys(); //返回此选择器的已选择键集
            it = keys.iterator();
           // 遍历,为每一个客户服务 
            while(it.hasNext()) 
            {
               key = (SelectionKey)it.next();
               if(key.isReadable())
               { // 测试此键的通道是否已准备好进行读取。
                  int bytes;
                  client = (SocketChannel)key.channel();//返回为之创建此键的通道。
                  buffer.clear(); // 清空缓冲区中的内容,设置好position,limit,准备接受数据
                  bytes = client.read(buffer); // 从通道中读数据到缓冲中,返回读取得字节数
                  if(bytes >= 0) 
                  {
                     buffer.flip(); // 准备将缓冲中的数据写回到通道中
                     client.write(buffer);  // 数据写回到通道中
                  } 
                  else if(bytes < 0) 
                  { // 如果返回小于零的值代表读到了流的末尾
                     clients.remove(client);
                  // 通道关闭时,选择键也被取消
                     client.close();
                  }
               }
            }
         }
    }
    
   
    // 配置和注册代表客户连接的通道对象
    public void registerClient(SocketChannel client) throws IOException
    {
        client.configureBlocking(false);  // 设置非阻塞模式    
        client.register(readSelector, SelectionKey.OP_READ); //注册到选择器上
        clients.add(client); //保存这个通道对象----->为了写完数据时,删掉这个通道。
    }
   
    
    //服务器开始监听端口,提供服务
    public void listen() throws IOException
    { 
        ServerSocket socket;
        SocketChannel client;
        channel = ServerSocketChannel.open(); // 打开通道
        socket = channel.socket();   //得到与通道相关的ServerSocket对象
        socket.bind(new InetSocketAddress(port), 10);//将ServerSocket绑定在制定的端口上
        channel.configureBlocking(false); //配置通道使用非阻塞模式。
        
        try 
        {
            while(true) 
            {
            //与通常的程序不同,这里使用ServerSocketChannel.accpet()接受客户端连接请求,
            //而不是在ServerSocket对象上调用accept()。
                client = channel.accept();  //接受到此通道套接字的连接。  
                if(client != null)
                {
                    registerClient(client); // 注册客户信息
                }
                serviceClients();  // 为以连接的客户服务
            }
        } 
        finally 
        {
            socket.close(); // 关闭socket,关闭socket会同时关闭与此socket关联的通道
        }
    }
    
    
    
    
    public static void main(String[] args) throws IOException 
    {
        System.out.println("服务器启动");
        SelectorServer server = new SelectorServer(SelectorServer.DEFAULT_SERVERPORT);
        server.listen(); //服务器开始监听端口,提供服务
   
    }

}


基本过程:  服务器启动并初始化(new SelectorServer),服务器开始监听,serversocketchannel接收socket连接,并注册到selector,然后提供serversocket服务。

 

 

其中selector 是 SelectableChannel 对象的多路复用器。很有必要了解selector。

serversocketchannel   和socketchannel是实现使用通道传输数据的基础条件

非阻塞模式的优势:

                            通道channel要么处于阻塞 模式,要么处于非阻塞模式。

                            在阻塞模式中,每一个 I/O 操作完成之前都会阻塞在这个通道上调用的其他 I/O 操作。

                            在非阻塞模式中,永远不会阻塞 I/O 操作,并且传输的字节可能少于请求的数量,或者可能根本不传输字节。

                            新创建的通道总是处于阻塞模式。在结合使用基于选择器selector的多路复用时,非阻塞模式是最有用的。向选择器

                            注册某个通道前,必须将该通道置于非阻塞模式,并且在注销之前可能无法返回到阻塞模式。

        

 

 


本文转载自:http://blog.csdn.net/caiwenfeng_for_23/article/details/8454013

蜀山下的鱼
粉丝 9
博文 405
码字总数 0
作品 0
广州
高级程序员
私信 提问
JAVA NIO non-blocking模式实现高并发服务器

Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要讲的是如何使用NIO的网络新特性,来构建高性能非阻塞并发服务器. 文章基于个人理解,我也来搞搞NIO.,...

Mr&Cheng
2013/01/30
3.5K
1
从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一)

从Jetty、Tomcat和Mina中提炼NIO构架网络服务器的经典模式(一) 收藏 如何正确使用NIO来构架网络服务器一直是最近思考的一个问题,于是乎分析了一下Jetty、Tomcat和Mina有关NIO的源码,发现...

光石头
2011/02/20
733
0
浅谈“阻塞同步”,“BIO、NIO、AIO”

一、阻塞?同步? 可能大家平常会经常听到这两个名词,但是没花太多心思详细了解,今天就来揭开这层面纱。 一次IO操作,以read方法举例,会经历两个阶段: (1)等待数据准备(Waitingfor the...

叫我宫城大人
2017/09/04
0
0
JAVA NIO non-blocking模式实现高并发服务器

Java自1.4以后,加入了新IO特性,NIO. 号称new IO. NIO带来了non-blocking特性. 这篇文章主要讲的是如何使用NIO的网络新特性,来构建高性能非阻塞并发服务器. 文章基于个人理解,我也来搞搞NIO.,...

xpbug
2013/01/10
7.4K
4
WebSocket服务器--CshBBrain

宝贝鱼(CshBBrain) 是一个来自中国的简单的轻量级的高性能的WebSocket服务器。支持服务器集群,能满足大并发量高容量的分布式系统开发。如果你需要开发带有集群功能的WebSocket服务器,宝贝鱼...

cshbbrain
2012/09/28
15K
17

没有更多内容

加载失败,请刷新页面

加载更多

前端技术之:Prisma Demo服务部署过程记录

安装前提条件: 1、已经安装了docker运行环境 2、以下命令执行记录发生在MackBook环境 3、已经安装了PostgreSQL(我使用的是11版本) 4、Node开发运行环境可以正常工作 首先需要通过Node包管...

popgis
今天
5
0
数组和链表

数组 链表 技巧一:掌握链表,想轻松写出正确的链表代码,需要理解指针获引用的含义: 对指针的理解,记住下面的这句话就可以了: 将某个变量赋值给指针,实际上就是将这个变量的地址赋值给指...

code-ortaerc
今天
4
0
栈-链式(c/c++实现)

上次说“栈是在线性表演变而来的,线性表很自由,想往哪里插数据就往哪里插数据,想删哪数据就删哪数据...。但给线性表一些限制呢,就没那么自由了,把线性表的三边封起来就变成了栈,栈只能...

白客C
今天
43
0
Mybatis Plus service

/** * @author beth * @data 2019-10-20 23:34 */@RunWith(SpringRunner.class)@SpringBootTestpublic class ServiceTest { @Autowired private IUserInfoService iUserInfoS......

一个yuanbeth
今天
5
0
php7-internal 7 zval的操作

## 7.7 zval的操作 扩展中经常会用到各种类型的zval,PHP提供了很多宏用于不同类型zval的操作,尽管我们也可以自己操作zval,但这并不是一个好习惯,因为zval有很多其它用途的标识,如果自己...

冻结not
昨天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部