一  基本概念
  1. IO(BIO)和NIO的区别:其本质就是阻塞和非阻塞的区别。
    阻塞:应用程序在获取网络数据的时候,如果网络传输数据很慢,那程序就一直等着,直到传输完毕为止。
    非阻塞:应用程序直接可以获取已经准备就绪的数据,无需等待。
    IO为同步阻塞形式,NIO为同步非阻塞,到JDK1.7,NIO为异步非阻塞。
    同步是指应用程序直接参与IO读写;异步是指操作系统操作IO,应用程序直接取结果。
    同步说的是server服务器端的执行方式; 阻塞说的是具体的技术,接受数据的方式。
  1. NIO基于Buffer(缓冲区)、Channel(管道)、Selector(选择器)。
    2.1 Buffer:实质上是一个数组,它为缓冲区提供了数据操作的概念,如位置、容量等。除Boolean外,每一种java基本类型都对应了一种缓冲区。
    2.2 Channel:类似水管,网络数据通过Channel读取和写入。
      通道是双向的,流是单向的。
      通道可用于读、写或两者同时进行。
      通道可以与多路复用器结合,有多种状态位,方便多路复用器识别。
      通道分为两大类:网络读写(SelectableChannel);
      文件操作(FileChannel);
 
  3. Selector:多路复用器(selector),他是NIO编程的基础,非常重要。多路复用器提供选择已经就绪的任务的能力。

  简单说,就是selector会不断地轮询注册在其上的通道(channel),如果某个通道发生了读写操作,这个通道就处于就绪状态,会被selector轮询出来,然后通过selectionKey可以取得就绪的channel集合,从而进行后续的IO操作。
  一个多路复用器(selector)可以负责成千上万channel通道,没有上限,这也是JDK使用了epoll代替了传统的select实现,获取连接句柄没有限制。这也就意味着我们只要一个线程负责selector的轮询,就可以接入成千上万个客户端,这就是JDK NIO库的巨大进步。

  (扩展——Epoll是什么:epoll是Linux内核为处理大批量文件描述符而作了改进的poll,是Linux下多路复用IO接口select/poll的增强版本,它能显著提高程序在大量并发连接中只有少量活跃的情况下的系统CPU利用率。另一点原因就是获取事件的时候,它无须遍历整个被侦听的描述符集,只要遍历那些被内核IO事件异步唤醒而加入Ready队列的描述符集合就行了。epoll除了提供select/poll那种IO事件的水平触发(Level Triggered)外,还提供了边缘触发(Edge Triggered),这就使得用户空间程序有可能缓存IO状态,减少epoll_wait/epoll_pwait的调用,提高应用程序效率。)

  selector线程就类似一个管理者(master),管理成千上万个管道,然后轮询哪个管道的数据已经准备好,通知cpu执行IO的读取或写入操作。
selector模式:当IO事件(管道)注册到选择器以后,selector会分配给每个管道一个key值,相当于标签。selector选择器是以轮询的方式进行查找注册的所有IO事件(管道),当我们的IO事件(管道)准备就绪后,select就会识别,会通过key值来找到相应的管道,进行相关的数据处理操作(从管道里读或写数据,写到我们的数据缓冲区中)。
每个管道都会对选择器进行注册不同的事件状态,以便选择器查找。

  SelectionKey.OP_CONNECT

  SelectionKey.OP_ACCEPT

  SelectionKey.OP_READ

  SelectionKey.OP_WRITE

面试常问:Bio——NIO——AIO区别和进化过程

 
二  Netty
 
简单强大的NIO框架,异步。可以快速开发网络应用,如服务器和客户端协议。简单实现点我参考
1、TCP粘包、拆包问题

  熟悉tcp编程的可能都知道,无论是服务器端还是客户端,当我们读取或者发送数据的时候,都需要考虑tcp底层的粘包/拆包机制。
  tcp是一个“流”协议,所谓流就是没有界限的一串数据。大家可以想象下如果河里的水就好比数据,他们是连成一片的,没有分界线。tcp底层并不了解上层的业务数据具体的含义,它会根据tcp缓冲区的实际情况进行包的划分,也就是说,在业务上,我们一个完整的包可能会被tcp分成多个包进行发送,也可能把多个小包封装成一个大的数据包发送出去,这就是所谓的tcp粘包、拆包问题。
  分析tcp粘包、拆包问题的产生原因
    1.应用程序write写入的字节大小大于套接口发送缓冲区的大小
    2.进行MSS大小的TCP分段
    3.以太网帧的payload大于MTU进行IP分片

  拆包的三种解决方案
    1.消息定长,例如每个报文的大小固定为200个字节,如果不够,空位补空格。
    2.在包尾部增加特殊字符进行分割,例如加回车等。
    3.将消息分为消息头和消息体,在消息头中包含表示消息总长度的字段,然后进行业务逻辑的处理

  拆包具体实现可以用两个类
    1.分隔符类:DelimiterBasedFrameDecoder(自定义分隔符)
    2.FixedLengthFrameDecoder(定长)

2、Netty编解码技术
      编解码技术,说白了就是Java序列化技术,序列化目的就两个,第一是进行网络传输,第二是对象持久化。
      虽然我们可以使用Java进行对象序列化,netty去传输,但是Java序列化的硬伤太多,比如Java序列化没法跨语言、序列化后码流太大、序列化性能太低等等
      主流的编解码框架:
        JBoss的Marshalling包(是一个Java对象序列化包,对JDK默认的序列化框架进行了优化,又保持了跟java.io.serializable接口的兼容,同时增加了一些可调参数,与netty结合后进行序列化对象的代码编写很简单)
        google的protobuf
        基于protobuf的Kyro
        MessagePack框架

3、Netty主要应用场景

  1.数据通信  

    两台及以上机器如何使用netty通信:
      1.使用长连接通道不断开的形式进行通信,也就是服务器和客户端的通道一直处于开启状态,如果服务器性能够好,并且客户端数量也比较少的情况下,推荐此方式。
      2.一次性批量提交数据,采用短连接方式。也就是我们会把数据保存在本地临时缓冲区或者临时表里,当达到临界值时进行一次性批量提交,又或者根据定时任务轮询提交,这种情况的弊端是做不到实时传输,对实时性要求不高的应用程序中可以推荐使用。
      3.我们可以使用一种特殊的长连接,在指定某一段时间之内,服务器与某台客户端没有任何通信,则断开连接。下次连接则是客户端向服务器发送请求的时候,再次建立连接。这种模式需要考虑两个因素,
        3.1如何在超时(即服务器和客户端没有任何通信)后关闭通道,关闭后又该如何再次建立连接
        3.2客户端宕机时,我们不用管,下次客户端重启之后我们就可以与服务器建立连接,但当服务器宕机时,我们的客户端如何与服务器进行连接

  2.心跳测试

    我们使用socket通信一般会经常处理多个服务器之间的心跳检测,一般服务器集群,会有一台或多台主机(master),和多台从机(slave),那么主机肯定要时时刻刻知道自己下面的从机的各方面情况,然后进行实时监控的功能,这个在分布式架构里叫做心跳检测或心跳监控。最佳处理方案还是使用一些通信框架进行实现,如netty。

  3.文件上传下载

附:Mina是一个和netty类似的框架,它属于Apache。

开发进阶系列:Java网络通信编程从基础到框架的更多相关文章

  1. 【Xamarin开发 Android 系列 7】 Android 结构基础(下)

    原文:[Xamarin开发 Android 系列 7] Android 结构基础(下) *******前期我们不打算进行太深入的东西,省的吓跑刚进门的,感觉门槛高,so,我们一开始就是跑马灯一样,向前 ...

  2. 【TCP/IP】之Java socket编程API基础

    Socket是Java网络编程的基础,深入学习socket对于了解tcp/ip网络通信协议很有帮助, 此文讲解Socket的基础编程.Socket用法:①.主要用在进程间,网络间通信. 文章目录如下: ...

  3. Java程序员从笨鸟到菜鸟之(十三)java网络通信编程

    本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 首先声明一下,刚开始学习java网络通信编程就对他有一种畏惧感,因为自己对网络一窍不通,所 ...

  4. 【Xamarin开发 Android 系列 6】 Android 结构基础(上)

    原文:[Xamarin开发 Android 系列 6] Android 结构基础(上) 前面大家已经熟悉了什么是Android,而且在 [Xamarin开发 Android 系列 4] Android ...

  5. java并发编程 线程基础

    java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...

  6. 推荐扔物线的HenCoder Android 开发进阶系列 后期接着更新

    官网地址:http://hencoder.com/ 我来做一次辛勤的搬运工 HenCoder:给高级 Android 工程师的进阶手册 HenCoder Android 开发进阶: 自定义 View ...

  7. Java并发编程核心方法与框架-CountDownLatch的使用

    Java多线程编程中经常会碰到这样一种场景:某个线程需要等待一个或多个线程操作结束(或达到某种状态)才开始执行.比如裁判员需要等待运动员准备好后才发送开始指令,运动员要等裁判员发送开始指令后才开始比赛 ...

  8. java网络通信编程

    网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据,这个就是狭义的网络编程范畴.在发送和接收数据时,大部分的程序设计语言都设 ...

  9. Java Socket编程----网络基础

    详见:https://www.cnblogs.com/rocomp/p/4790340.html Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而 ...

  10. Java 并发编程实践基础 读书笔记: 第二章 构建线程安全应用程序

    1,什么是线程安全性? 简单概括就是一个类在多线程情况下能安全调用就是线程安全 2,Servlet  的线程安全性  默认是非线程安全的,写servlet代码的时候需要注意线程安全,注意同步 3,vo ...

随机推荐

  1. JS Leetcode 81. 搜索旋转排序数组 II 题解,补救二分法的可行性

    壹 ❀ 引 今日LeetCode题为153. 寻找旋转排序数组中的最小值,在10个月前,我已在JS leetcode 寻找旋转排序数组中的最小值 题解分析,你不得不了解的二分法一文中写了本题的题解,所 ...

  2. JS leetcode 加一 题解分析

    壹 ❀ 引 今天是刷leetcode的第三天,根据推荐优先刷数据结构相关的卡片,先把数据结构知识体系建立起来,不然就是题目无从下手答案也看不懂的尴尬局面.那么今天的题目是加一,老规矩,先记录自己的解题 ...

  3. NC25879 外挂

    题目链接 题目 题目描述 我的就是我的,你也是我的,记住了,狐狸! ​ --韩信-白龙吟 对于打赌输了的小T会遭受到制裁,小s修改了数据库使他可以派出许多军队来围攻小T. 很不幸,小T与小s打赌打输了 ...

  4. python 学习随笔1121

    Python 数据处理几个好用又简单的库: json re string pandas 与系统交互: subprocess os

  5. Python 写入文件、读取文件内容——open函数/readLines/Write/find函数用法

    1.读取.txt整个文件 ww.txt文件在程序文件所在的目录,在文件存储在其他地方,ww.txt需要添加文件路径,如:E:\book1\ww.txt:读取后希望返回的是列表类型,将read改为rea ...

  6. Python异步编程原理篇之IO多路复用模块selector

    selector 简介 selector 是一个实现了IO复用模型的python包,实现了IO多路复用模型的 select.poll 和 epoll 等函数. 它允许程序同时监听多个文件描述符(例如套 ...

  7. 栈溢出-ret2libc地址泄露笔记

    作为一名初学者,在碰到很多攻击思路的时候会感觉很妙,比如gadget的构造,这题的sh参数截断. 1.首先分析程序架构和保护措施. 2.使用IDA开始判断程序是否具备最简单的栈溢出执行条件: ret2 ...

  8. Redis客户端汇总

    编程客户端 已经支持了许多编程语言,详见:https://redis.io/docs/clients/ 图形客户端 1.Another Redis Desktop Manager 支持哨兵, 集群, ...

  9. go最新版本1.15安装配置及编辑器2020.2版本goland

    下载 https://golang.google.cn/dl/ 配置 go env #查看是否安装成功 # 终端输入修改镜像地址 $ go env -w GO111MODULE=on $ go env ...

  10. 【应用服务 App Service】App Service For Linux 中如何挂载一个共享文件夹呢? Mount Azure Storage Account File Share

    问题描述 使用Linux作为服务器运行Web App时,如何将 Storage Account 作为本地共享装载到 App Service for  Linux / Container 中的应用呢? ...