先来看一下本篇博文的目录:

一:简介Nio

二:Nio的好处

三:关于http协议

四:代码实现

五:总结

一:简介Nio

我们都知道io流,那么NIO是什么呢?本篇博文将会带你一探NIO,NIO的全称叫做New IO,顾名思义也就是全新的IO流,从Java Api 1.4版本开始发行的,nio提供了完全不同的工作体制,java nio的IO模型是同步非阻塞,也就是当用户发起一个IO操作后,边可等待边可返回,但是需要进程不断的询问是否传输完毕,这就引入了不必要的cpu浪费,但是总体它的效率是要高于IO的,它主要有三大核心组件:

  • Channels
  • Buffers
  • Selectors

channel你可以理解为一个通道,就相当于数据传输的管道,你可以如此抽象的理解。Buffers是一个缓存区,数据可以通过管道到缓冲区,也可以通读缓冲区到channel,Nio的主要实现类为FileChannel、DatagramChannel、SocketChannel、ServerSocketChannel,BUffer的主要实现类为,从中可以看出包含了java的很多基本类型数据,Byte、char、double、Folat、int、long等,ByteBuffer,CharBuffer,DoubleBuffer,FloatBuffer,IntBuffer,LongBuffer,ShortBuffer。而Selector是Nio最关键的一个部分,Selector 允许单线程处理多个 Channel,如果你的应用打开了多个连接(通道),但每个连接的流量都很低,使用 Selector 就能极大的提升效率。要使用 Selector,得向 Selector 注册 Channel,然后调用它的 select()方法。这个方法会一直阻塞到某个注册的通道有事件就绪。一旦这个方法返回,线程就可以处理这些事件,事件的例子有如新连接进来,数据接收等

二:nio的好处

传统的socket IO中,需要为每个连接创建一个线程,当并发的连接数量非常巨大时,线程所占用的栈内存和CPU线程上下文切换的开销将非常巨大。使用NIO,不再需要为每个连接创建单独的线程,可以用一个含有限数量线程的线程池,甚至一个线程来为任意数量的连接服务。由于线程数量小于连接数量,所以每个线程进行IO操作时就不能阻塞,如果阻塞的话,有些连接就得不到处理,NIO提供了这种非阻塞的能力。当有任务进程来,可以实现通道注册到Selector上,一个Slector可以管理多个线程,这样就避免了线程的上下文切换,避免了资源的浪费,大大的提升了效率。

三:关于http协议

http从1990年开始,目前已经经历3代,最近使用的http1.1,https其实就是实际上的http1.2,当然本篇主要关注的还是http1.1,http协议,我们每天用到的非常多,它是基于服务器和客户端模式的,它在应用层解析内容的,它有点类似于我们的电报,比如在发送之前需要加密报文,发送到目的地需要解析报文,对应的我们网站,其实每次我们点一下链接进行请求就是进行了一次http的request操作,这是对于客户端而言的,这一过程就将会携带有你请求的地址、host主机名、用户的状态,sessionid、cookie等信息(具体我们可以用程序来实现),然后发送到服务器,服务器进行解析,然后给我们返回。学习http协议,我们要记得以下两点:

1.无连接:无连接的含义是限制每次连接只处理一个请求。服务器处理完客户的请求,并收到客户的应答后,即断开连接。采用这种方式可以节省传输时间。
2.无状态:HTTP协议是无状态协议。无状态是指协议对于事务处理没有记忆能力。缺少状态意味着如果后续处理需要前面的信息,则它必须重传,这样可能导致每次连接传送的数据量增大。另一方面,在服务器不需要先前信息时它的应答就较快

四:代码实现

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.util.Iterator; public class Server { public static void main(String[] args) throws IOException { ServerSocketChannel ssc = ServerSocketChannel.open();//监听新进来的 TCP连接的通道,打开 ServerSocketChannel ssc.socket().bind(new InetSocketAddress(8080));//绑定8080端口 ssc.configureBlocking(false);//设置非阻塞模式 Selector selector = Selector.open();//创建选择器 SelectionKey selectionKey = ssc.register(selector, SelectionKey.OP_ACCEPT);//给选择器注册通道 //selectionKey:代表了注册到该 Selector 的通道 while (true) { //监听新进来的连接 int select = selector.select(2000);
if (select==0) { //如果选择的通道为0,最长会阻塞 timeout毫秒 System.out.println("等待请求超时......"); continue;
} System.out.println("开始处理请求....."); Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator();//迭代器 while (keyIter.hasNext()) { SelectionKey key = keyIter.next(); new Thread(new HttpHandler(key)).run(); keyIter.remove(); }
}
}
}
package com.wyq.NioToHttp;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset; /**
* Http处理器器
* @author Yiron
*
*/
public class HttpHandler implements Runnable{ private int buffersize= 1024;//设置缓冲区大小 private String localCharSet="UTF-8"; //设置编码格式 private SelectionKey key;//注册号的通道 public HttpHandler(SelectionKey key) {//把选择键构造进去 this.key = key;
} public void handleAccept() throws IOException{ SocketChannel socketChannel=((ServerSocketChannel)key.channel()).accept(); socketChannel.configureBlocking(false);//设置非阻塞模式 socketChannel.register(key.selector(), SelectionKey.OP_READ,ByteBuffer.allocate(buffersize));
//buffer分配一个缓冲区 大小为1024 } public void handleRead() { SocketChannel sc=(SocketChannel)key.channel();// SocketChannel 是一个连接到 TCP 网络套接字的通道 ByteBuffer buffer=(ByteBuffer)key.attachment();//从 SocketChannel读取到的数据将会放到这个 buffer中 buffer.clear(); try {
if((sc.read(buffer))!=-1) { buffer.flip();//flip方法将Buffer从写模式切换到读模式 String receive = Charset.forName(localCharSet).newDecoder().decode(buffer).toString();
//将此 charset 中的字节解码成 Unicode 字符 String[] requestMessage = receive.split("\r\n");//接受请求的信息 for (String message : requestMessage) { if (message.isEmpty()) {//如果是空行说明信息已经结束了 break;
}
}
//控制台打印
String[] firsetLine = requestMessage[0].split(" "); System.out.println("----控制台输出:-------"); System.out.println("Method:t"+firsetLine[0]); System.out.println("url是:\t"+firsetLine[1]); System.out.println("Httpversion是:\t"+firsetLine[2]); System.out.println("-----输出结束-------------"); //返回客户端
StringBuilder sendStr = new StringBuilder(); sendStr.append("Http/1.1 200 Ok\r\n"); sendStr.append("Content-Type:text/html;charset="+localCharSet+"\r\n"); sendStr.append("\r\n"); sendStr.append("<html><head><title>显示报文</title></head><body>"); sendStr.append("接受到请求的报文是:+<br>"); for (String s : requestMessage) { sendStr.append(s+"<br/>"); }
sendStr.append("</body></html>"); buffer=ByteBuffer.wrap(sendStr.toString().getBytes(localCharSet)); sc.write(buffer); sc.close();
}else {
sc.close();
}
} catch (IOException e) { e.printStackTrace();
}
}
@Override
public void run() { try {
if (key.isAcceptable()) {//接受 handleAccept(); }
if (key.isReadable()) {//开始读 handleRead(); } } catch (Exception e) { e.printStackTrace();
}
}
}

打印控制台,输出如下:

开始处理请求.....
----控制台输出:-------
Method:tGET
url是: /
Httpversion是: HTTP/1.1

因为我们绑定了8080端口,这里进行请求,看浏览器会打印出相关的http信息,具体如下:

从中可以看出很多信息,比如我们的请求方式为:Get,主机为:localhost,端口为8080,连接状态:存活,接收的语言:中文-英文,cookile信息等等,这代表了我们请求的

头信息,将会把这些内容发送给浏览器。这就是http协议在request请求前组织的报文,从中我们可以一探http的究竟,这对我们理解客户端-服务器模式更加深刻。有助于我们

对于web网站的开发。

五:总结

本篇博文的主要思想是学习nio的使用方式,并且能够理解http协议,其具体的包含信息的细节,理解nio的好处,关于对同步阻塞模式的理解,如果去通过nio实现http协议,虽然nio在实际中使用的机会并不多,但是还是有助我们加深对管道流的理解,io的实现方式,记得我有次面试的时候,被问到Nio、BiO的区别,当时是很蒙圈的,因为不知道java中还有这么多的流处理方式。我们需要学习关于单选择器处理多线程的方式,还有去思考关于线程效率的问题,这都对我们大有裨益。

用NIO实现http协议的更多相关文章

  1. socker TCP UDP BIO NIO

    BIO:  Java 1.4 以前只有之中方式. bio:阻塞式IO, 一个 socker 连接占用一个 线程.如果 IO 阻塞,会在传输速度限制,这个线程也会一直等待在这里,等待从socker 的 ...

  2. ActiveMQ支持的消息协议

    ActiveMQ支持哪些协议 ActiveMQ支持多种协议传输和传输方式,允许客户端使用多种协议连接ActiveMQ支持的协议:AUTO,OpenWire,AMQP,Stomp,MQTT等Active ...

  3. ActiveMQ 笔记(五)ActiveMQ的传输协议

    个人博客网:https://wushaopei.github.io/    (你想要这里多有) 面试思考题: 默认的61616端口如何更改 你生产上的连接协议如何配置的?使用tcp吗? 一.Activ ...

  4. Java通过SSLEngine与NIO实现HTTPS访问

    Java使用NIO进行HTTPS协议访问的时候,离不开SSLContext和SSLEngine两个类.我们只需要在Connect操作.Connected操作.Read和Write操作中加入SSL相关的 ...

  5. 转:最近5年133个Java面试问题列表

    最近5年133个Java面试问题列表 Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来 ...

  6. Java笔试题解答和部分面试题

    面试类  银行类的问题 问题一:在多线程环境中使用HashMap会有什么问题?在什么情况下使用get()方法会产生无限循环? HashMap本身没有什么问题,有没有问题取决于你是如何使用它的.比如,你 ...

  7. 近5年133个Java面试问题列表

    Java 面试随着时间的改变而改变.在过去的日子里,当你知道 String 和 StringBuilder 的区别就能让你直接进入第二轮面试,但是现在问题变得越来越高级,面试官问的问题也更深入. 在我 ...

  8. Netty版本升级血泪史之线程篇

    1. 背景 1.1. Netty 3.X系列版本现状 根据对Netty社区部分用户的调查,结合Netty在其它开源项目中的使用情况,我们可以看出目前Netty商用的主流版本集中在3.X和4.X上,其中 ...

  9. c/c++字节序转换(转)

    字节序(byte order)关系到多字节整数(short/int16.int/int32,int64)和浮点数的各字节在内存中的存放顺序.字节序分为两种:小端字节序(little endian)和大 ...

随机推荐

  1. Robotframe work学习之初(二)

    一.F5帮助 Robot Framework 并没有像其它框架一样提供一份完整的 API 文档,所以,我们没办法通过官方 API文档进行习.RIDE 提供了 F5 快捷键来打开帮助文档. search ...

  2. 大麦盒子(domybox)无法进入系统解决方案!【简单几步】

    大麦无法进入系统解决方案![简单几步]前提准备:电脑一台盒子控制台软件盒子开机并联网并且盒子和电脑处于同一个路由器下的网络! 前提准备:电脑一台盒子控制台软件盒子开机并联网并且盒子和电脑处于同一个路由 ...

  3. Unity 类似FingerGestures 的相机跟随功能

    本文原创,转载请注明出处:http://www.cnblogs.com/AdvancePikachu/p/6555188.html 最近在做一款VR项目,有一个查看功能,分为自由查看和跟随查看. 自由 ...

  4. 设计模式(1)单例模式(Singleton)

    设计模式(0)简单工厂模式 源码地址 0 单例模式简介 0.0 单例模式定义 单例模式是GOF二十三中经典设计模式的简单常用的一种设计模式,单例模式的基本结构需满足以下要求. 单例模式的核心结构只有一 ...

  5. Web.简单配置

    XML 元素不仅是大小写敏感的,而且它们还对出现在其他元素中的次序敏感.所有这些元素都是可选的.因此,可以省略掉某一元素,但不能把它放于不正确的位置. icon icon元素指出IDE和GUI工具用来 ...

  6. 【openstack N版】——摘除一个计算节点

    1.查看计算节点 #查看所有计算节点 [root@open-control01 ~]# nova service-list+----+------------------+-------------- ...

  7. <JAVA>可变参数列表

    这是java1.5版本的新特性,就是当你想定义一个方法,但是不知道以后要用的时候传几个参数进去,这时可以在方法的参数列表中这样写(参数类型... 数组名),然后在方法内部直接用操作数组的方式操作.比如 ...

  8. Linux下安装Oracle的两种方式------有图形界面安装和静默安装

    本文参考文章 http://blog.csdn.net/zonej/article/details/50680857 http://blog.csdn.net/tongzidane/article/d ...

  9. 走进javascript——类型

    ECMAScript语言类型对应于使用ECMAScript语言的ECMAScript程序员直接操作的值.ECMAScript语言类型有以下几种Undefined,Null,Boolean,String ...

  10. 浅谈Web的流量控制

    想聊一聊流量控制,谈谈的重要性,解决了哪些业务问题,那我们问题来进入正题.   1.WEB容器如何流量控制?   一个Tomcat的容器,这个容器呢,部署在一台服务器上面,同时这台服务器的资源非常非常 ...