java 网络编程发展过程以及nio的特点
背景:
省分短信发送每天都差不多要1000W条上下,遇到特殊节假日和政府通告时量会更大!boss系统中存放的是短信发送内容,而真正完成发送短信指令动作是的华为方做的短厅,这么大的通信量选择了netty来完成数据传输并自定义了一套基于netty的SGIP协议进行通信;
省分boss系统—>短信营业厅();
基本知识
TCP/IP网络协议:
网上很多有关这个协议的解释,自行google,下面是简单的理解记忆:
tcp/ip的3次握手, 简单来说就是第一次我连接你给你一个标识SYN,你给我返回SYN并给一个新的ACK标记我,然后我再把ACK给你,
这样证明我们之前传东西是可靠,的然后就正式传数据了
图片来自网上
tcp/ip的4次挥手断开,相当于,你给我一个ACK我给你一个FIN,然后再次彼此交换确认,OK就可以结束通信了
java的socket就是对tcp/ip的一种实现
基础代码,:
一个简单的socket实现tcp/ip的样例,后面的BIO/NIO/AIO都是基本上于这个例子进行变化
client端:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {final static String ADDRESS = "127.0.0.1";final static int PORT = 7788;public static void main(String[] args) Socket socket = null;BufferedReader in = null;PrintWriter out = null;socket = new Socket(ADDRESS, PORT);in = new BufferedReader(new InputStreamReader(socket.getInputStream()));out = new PrintWriter(socket.getOutputStream(), true);//向服务器端发送数据out.println("接收到客户端的请求数据...");out.println("接收到客户端的请求数据1111...");String response = in.readLine();System.out.println("Client: " + response);...
Server端:
public class Server {final static int PROT = 7788;public static void main(String[] args) {ServerSocket server = null;server = new ServerSocket(PROT);System.out.println(" server start .. ");//进行阻塞Socket socket = server.accept();//新建一个线程执行客户端的任务new Thread(new ServerHandler(socket)).start();}}ServerHandler.java 如下:public class ServerHandler implements Runnable{private Socket socket ;public ServerHandler(Socket socket){this.socket = socket;}@Overridepublic void run() {BufferedReader in = null;PrintWriter out = null;try {in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));out = new PrintWriter(this.socket.getOutputStream(), true);String body = null;while(true){body = in.readLine();if(body == null) break;System.out.println("Server :" + body);out.println("服务器端回送响的应数据.");}}}
上面这个代码很简单转换成图型说明就是web浏览器发一个请求过来,web服务器就要new 一个线程来处理这个请求,这是传统的请求处理模型,这也就引来一个很大的问题,当请求越多,服务器端的启用线程也要越多,我们都知道linux(window)的文件句柄数有是限的,默认是1024,当然可以修改,上限好像是65536 ,(一个柄也相当于一个socket也相当于一个thread,linux查看文件句柄Unlimit -a) 其实在实际当中只要并发到1000上下响应请求就会很慢了,所以这种模型是有问题的,这种也就是同步阻塞IO编程(JAVA BIO)
网上查的定义:
同步阻塞IO(JAVA BIO):
同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销.
BIO—>NIO—->AIO的发展历程
上面的BIO是有问题的,也就是出现在jdk1.4那个古时代的产物,现在当然这要改进下,上面的问题无非就是服务器端的线程无限制的增长才会导致服务器崩掉,那我们就对征下药,加个线程池限制线程的生成,又可以复用空闲的线程,是的,在jdk1.5也是这样做的,下面是服务器端改进后的代码:
public class Server {final static int PORT = 7788;public static void main(String[] args) {ServerSocket server = null;BufferedReader in = null;PrintWriter out = null;server = new ServerSocket(PORT);System.out.println("server start");Socket socket = null;HandlerExecutorPool executorPool = new HandlerExecutorPool(50, 1000);while(true){socket = server.accept();executorPool.execute(new ServerHandler(socket));}}}HandlerExecutorPool.javaimport java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class HandlerExecutorPool {private ExecutorService executor;public HandlerExecutorPool(int maxPoolSize, int queueSize){this.executor = new ThreadPoolExecutor(Runtime.getRuntime().availableProcessors(),maxPoolSize, 120L, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(queueSize));}public void execute(Runnable task){this.executor.execute(task);}
}
Jdk1.5创造了一个假的nio 用一个HanderExecutorPool来限定了线程数量,但只是解决了服务器端不会因为并发太多而死掉,但解决不了并发大而响应越来越慢的,到时你也会怀疑你是不是真的用了一个假的nio!!!!!!!
为了解决这个问题,就要用三板斧来解决!
别急,要解决一个诸葛亮,你必先要造三个臭皮匠,先引入3个NIO相关概念先!
1> Buffer 缓冲区
难用的buffer是一个抽象的对象,下面还有ByteBuffer,IntBuffer,LongBuffer等子类,相比老的IO将数据直接读/写到Stream对象,NIO是将所有数据都用到缓冲区处理,它本质上是一个数组,提供了位置,容量,上限等操作方法,还是直接看代码代码来得直接
InetSocketAddress address = new InetSocketAddress("127.0.0.1", 7788);//创建连接的地址SocketChannel sc = null;//声明连接通道ByteBuffer buf = ByteBuffer.allocate(1024);//建立缓冲区sc = SocketChannel.open();//打开通道sc.connect(address);//进行连接while(true){//定义一个字节数组,然后使用系统录入功能:byte[] bytes = new byte[1024];System.in.read(bytes);buf.put(bytes);//把数据放到缓冲区中buf.flip();//对缓冲区进行复位sc.write(buf);//写出数据buf.clear();//清空缓冲区数据}
2>Channel 通道
如自来水管一样,支持网络数据从Channel中读写,通道写流最大不同是通道是双向的,而流是一个方向上移动(InputStream/OutputStream),通道可用于读/写或读写同时进行,它还可以和下面要讲的selector结合起来,有多种状态位,方便selector去识别. 通道分两类,一:网络读写(selectableChannel),另一类是文件操作(FileChannel),我们常用的是上面例子中的网络读写!
3>Selector 多路复用选择器
它是神一样存在的东西,多路复用选择器提供选择已经就绪的任务的能力,也就是selector会不断轮询注册在其上的通道(Channel),如果某个通道发生了读写操作,这个通道处于就绪状态,会被selector轮询出来,然后通过selectionKey可以取得就绪的Channel集合,从而进行后续的IO操作.
一个多路复用器(Selector)可以负责成千上万个Channel,没有上限,这也是JDK使用epoll代替了传统的selector实现,获得连接句柄没有限制.这也意味着我们只要一个线程负责selector的轮询,就可以接入成千上万个客户端,这是JDK,NIO库的巨大进步.
来张精心整好的图
这个学习进到深水区了,注意罗,下面是服务器端的代码,上面例子代码是client端的,看里面的注解,如果还不明白,多看几次,代码是可运行的,记得要jdk1.7以上版本,多运行,自己意会下,我也只帮到这了!
import java.io.IOException;
import java.net.InetSocketAddress;
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;public class Server implements Runnable{//1 多路复用器(管理所有的通道)private Selector seletor;//2 建立缓冲区private ByteBuffer readBuf = ByteBuffer.allocate(1024);//3 private ByteBuffer writeBuf = ByteBuffer.allocate(1024);public Server(int port){try {//1 打开路复用器this.seletor = Selector.open();//2 打开服务器通道ServerSocketChannel ssc = ServerSocketChannel.open();//3 设置服务器通道为非阻塞模式ssc.configureBlocking(false);//4 绑定地址ssc.bind(new InetSocketAddress(port));//5 把服务器通道注册到多路复用器上,并且监听阻塞事件ssc.register(this.seletor, SelectionKey.OP_ACCEPT);System.out.println("Server start, port :" + port);} catch (IOException e) {e.printStackTrace();}}@Overridepublic void run() {while(true){try {//1 必须要让多路复用器开始监听this.seletor.select();//2 返回多路复用器已经选择的结果集Iterator<SelectionKey> keys = this.seletor.selectedKeys().iterator();//3 进行遍历while(keys.hasNext()){//4 获取一个选择的元素SelectionKey key = keys.next();//5 直接从容器中移除就可以了keys.remove();//6 如果是有效的if(key.isValid()){//7 如果为阻塞状态if(key.isAcceptable()){this.accept(key);}//8 如果为可读状态if(key.isReadable()){this.read(key);}//9 写数据if(key.isWritable()){//this.write(key); //ssc}}}} catch (IOException e) {e.printStackTrace();}}}private void write(SelectionKey key){//ServerSocketChannel ssc = (ServerSocketChannel) key.channel();//ssc.register(this.seletor, SelectionKey.OP_WRITE);}private void read(SelectionKey key) {try {//1 清空缓冲区旧的数据this.readBuf.clear();//2 获取之前注册的socket通道对象SocketChannel sc = (SocketChannel) key.channel();//3 读取数据int count = sc.read(this.readBuf);//4 如果没有数据if(count == -1){key.channel().close();key.cancel();return;}//5 有数据则进行读取 读取之前需要进行复位方法(把position 和limit进行复位)this.readBuf.flip();//6 根据缓冲区的数据长度创建相应大小的byte数组,接收缓冲区的数据byte[] bytes = new byte[this.readBuf.remaining()];//7 接收缓冲区数据this.readBuf.get(bytes);//8 打印结果String body = new String(bytes).trim();System.out.println("Server : " + body);// 9..可以写回给客户端数据 } catch (IOException e) {e.printStackTrace();}}private void accept(SelectionKey key) {try {//1 获取服务通道ServerSocketChannel ssc = (ServerSocketChannel) key.channel();//2 执行阻塞方法SocketChannel sc = ssc.accept();//3 设置阻塞模式sc.configureBlocking(false);//4 注册到多路复用器上,并设置读取标识sc.register(this.seletor, SelectionKey.OP_READ);} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {new Thread(new Server(7788)).start();;}}
如果你理解了Java NIO ,下面讲的netty也是水到渠成的事,只想说,深水区已过了!
差点忘记还要补下AIO的,这个比NIO先进的技术,最终实现了
netty
这是神一样存在的java nio框架, 这个偏底层的东西,可能你接触较少却又无处不在,比如:
在业界有一篇无法超越的netty入门文章,我也没这个能力超越,只能双手奉上,你们好好研读,必然学有所成!
http://ifeve.com/netty5-user-guide/
还有杭州华为的李林锋写的 Netty权威指南 ,我是买了一本,不知如何评论好,中等吧!
刚好,我这边要修改的项目也是华为的………………
未完,先发…………………………………..
————————————————
版权声明:本文为CSDN博主「六楼外的风景」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/yangfanend/article/details/55100327
java 网络编程发展过程以及nio的特点相关推荐
- Java网络编程(6)NIO - Channel详解
前言 NIO的三个核心组件:Buffer.Channel.Selector Java网络编程(4)NIO的理解与NIO的三个组件完成了大概的了解 Java网络编程(5)NIO - Buffer详解详细 ...
- Java网络编程------IO模型的同步/异步/阻塞/非阻塞(1)
IO模型的同步/异步/阻塞/非阻塞 一.同步/异步/阻塞/非阻塞 1.同步和异步 2.阻塞和非阻塞 3.同步.异步和阻塞.非阻塞组合 二.IO 1.I/O 2.阻塞IO和非阻塞IO 3.同步IO和同步 ...
- Java网络编程与NIO学习总结
#Java网络编程与NIO学习总结 这篇总结主要是基于我之前Java网络编程与NIO系列文章而形成的的.主要是把重要的知识点用自己的话说了一遍,可能会有一些错误,还望见谅和指点.谢谢 #更多详细内容可 ...
- NIO详解(一):java网络编程IO总结(BIO、NIO、AIO)
1.基本概念 在Java网络通信中,最基本的概念就是Socket编程了.Socket又称"套接字" 向网络发出请求或者应答网络请求. Socket 和ServerSocket类库位 ...
- Java 网络编程系列之 NIO
Java 网络编程系列之 NIO 第 1 章Java NIO 概述 1.1 IO 概述 IO 的操作方式 1.2 阻塞 IO (BIO) 1.3 非阻塞 IO(NIO) 1.4 异步非阻塞 IO(AI ...
- Java网络编程和NIO详解开篇:Java网络编程基础
老曹眼中的网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为我们拥有网络.网络是一个神奇的东西,它改变了你和我的 ...
- python网络编程视频教程_Java网络开发视频教程 – 一站式学习Java网络编程视频教程 全面理解BIO(无密)...
Java网络开发视频教程 – 一站式学习Java网络编程视频教程 全面理解BIO(无密) 全面理解BIO/NIO/AIO 网络层编程,是每一个开发者都要面对的技术.课程为解决大家学习网络层知识的难题, ...
- JAVA网络编程知识学习
JAVA网络编程知识学习 学习目标 第一章 网络编程入门 1.1软件结构 1.2 网络通信协议 1.3 协议分类 1.4 网络编程三要素 协议 IP地址 IP地址分类 常用命令 端口号 InetAdd ...
- java网络编程_Java网络编程进阶:通过JSSE创建安全的数据通信
小编说:本文作者孙卫琴,知名IT作家和Java专家.本文将通过一个范例向大家介绍JSSE是如何实现安全的网络通信的. 在网络上,信息在由源主机到目标主机的传输过程中会经过其他计算机.一般情况下,中间的 ...
- 菜鸟学习笔记:Java提升篇9(网络1——网络基础、Java网络编程)
菜鸟学习笔记:Java提升篇9(网络1--网络基础.Java网络编程) 网络基础 什么是计算机网络 OS七层模型 Java网络编程 InetAddress InetSocketAddress URL类 ...
最新文章
- java集合中对象某属性比较排序
- 一个用泛型隐式传递权限关键字的方法
- 利用SparkSQL(java版)将离线数据或实时流数据写入hive的用法及坑点
- eclipse创建python项目提示Project interpreter not specified
- 【Linux常用命令】grep命令
- IE的2像素偏差问题终于“将要”成为历史了(附js微技巧一则)
- iframe去边框,无边框。使用大全
- 每日算法系列【LeetCode 289】生命游戏
- 什么原因导致MacBook Pro过热?如何解决这一问题?
- 关于"舆情监测"关键词在百度搜索中的相关数分析
- Qt —— QWebEngineView加载谷歌离线地图(包含离线地图瓦片下载制作)
- python深度学习基于pytorch——arange、linspace 函数生成数组
- 基于单目视觉的平面目标定位和坐标测量 (上) - 坐标系和成像模型
- 切尔诺贝利_切尔诺贝利泰坦尼克号的自然恢复历史以及复杂系统的课程
- 香港理工大学计算机专业课程,香港理工大学计算机系包括哪些专业
- 底部点击加载更多功能的简单实现
- MEM/MBA数学强化(08)数据分析
- data analysis (summary next step)
- 阿里云最新价格表,域名新购,续费,转入价格表分享
- IDEA不显示git版本控制以及vcs的配置
热门文章
- oracle查询语句转sql,将sql server查询语句转换为oracle查询语句[紧急]
- 15拆分成3个不同的自然数_素数大概有多少个?15岁的高斯翻过素数表之后给出了答案...
- 翻译: Transfer learning 迁移学习指南
- Google Code Review 浏览评论中的CL
- Impala 的特点
- 语义分割Swin Transformer
- 8. 字符串转整数 (atoi)
- 在排序数组中查找数字
- 过拟合的含义、出现原因及解决方案
- 《基 于 N Gram 的无词典 中文分词算法》 n-gram读感