开发进阶系列:Java网络通信编程从基础到框架
- IO(BIO)和NIO的区别:其本质就是阻塞和非阻塞的区别。
- NIO基于Buffer(缓冲区)、Channel(管道)、Selector(选择器)。
简单说,就是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区别和进化过程
熟悉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网络通信编程从基础到框架的更多相关文章
- 【Xamarin开发 Android 系列 7】 Android 结构基础(下)
原文:[Xamarin开发 Android 系列 7] Android 结构基础(下) *******前期我们不打算进行太深入的东西,省的吓跑刚进门的,感觉门槛高,so,我们一开始就是跑马灯一样,向前 ...
- 【TCP/IP】之Java socket编程API基础
Socket是Java网络编程的基础,深入学习socket对于了解tcp/ip网络通信协议很有帮助, 此文讲解Socket的基础编程.Socket用法:①.主要用在进程间,网络间通信. 文章目录如下: ...
- Java程序员从笨鸟到菜鸟之(十三)java网络通信编程
本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 首先声明一下,刚开始学习java网络通信编程就对他有一种畏惧感,因为自己对网络一窍不通,所 ...
- 【Xamarin开发 Android 系列 6】 Android 结构基础(上)
原文:[Xamarin开发 Android 系列 6] Android 结构基础(上) 前面大家已经熟悉了什么是Android,而且在 [Xamarin开发 Android 系列 4] Android ...
- java并发编程 线程基础
java并发编程 线程基础 1. java中的多线程 java是天生多线程的,可以通过启动一个main方法,查看main方法启动的同时有多少线程同时启动 public class OnlyMain { ...
- 推荐扔物线的HenCoder Android 开发进阶系列 后期接着更新
官网地址:http://hencoder.com/ 我来做一次辛勤的搬运工 HenCoder:给高级 Android 工程师的进阶手册 HenCoder Android 开发进阶: 自定义 View ...
- Java并发编程核心方法与框架-CountDownLatch的使用
Java多线程编程中经常会碰到这样一种场景:某个线程需要等待一个或多个线程操作结束(或达到某种状态)才开始执行.比如裁判员需要等待运动员准备好后才发送开始指令,运动员要等裁判员发送开始指令后才开始比赛 ...
- java网络通信编程
网络编程就是在两个或两个以上的设备(例如计算机)之间传输数据.程序员所作的事情就是把数据发送到指定的位置,或者接收到指定的数据,这个就是狭义的网络编程范畴.在发送和接收数据时,大部分的程序设计语言都设 ...
- Java Socket编程----网络基础
详见:https://www.cnblogs.com/rocomp/p/4790340.html Java最初是作为网络编程语言出现的,其对网络提供了高度的支持,使得客户端和服务器的沟通变成了现实,而 ...
- Java 并发编程实践基础 读书笔记: 第二章 构建线程安全应用程序
1,什么是线程安全性? 简单概括就是一个类在多线程情况下能安全调用就是线程安全 2,Servlet 的线程安全性 默认是非线程安全的,写servlet代码的时候需要注意线程安全,注意同步 3,vo ...
随机推荐
- 反悔贪心&模拟费用流
贪心是一种常用的算法,它能够获得局部最优解,但我们往往需要的是全局最优解,所以我们在贪心的时候加入和反悔的机制,让他能够得到全局最优解. 由于网络流中的退流操作本质上也是反悔贪心,所以在实现反悔贪心时 ...
- STM32F407VET6 / BLACK_F407VE开发板间隔0.5秒不断重启
有一块 STM32F407VET6 的故障开发板, 之前的问题是经常无法烧录, 必须reset之后才能连接, 具体查看这篇 STM32F407VET6烧录出现flash download failed ...
- 【framework】ATMS启动流程
1 前言 ATMS 即 ActivityTaskManagerService,用于管理 Activity 及其容器(任务.堆栈.显示等).ATMS 在 Android 10 中才出现,由原来的 A ...
- 常见Python问题及解决办法
文件编码问题 如果Python文件中存在中文注释,在运行时报错"SyntaxError: Non-ASCII character '\xe7' in file". 解决办法: 在文 ...
- 如何处理Long类型精度丢失问题?
一.现象与分析: 1.1. 现象 前后端交互,当后端传一些值给前端的时候,如果是long类型,有可能会出现数字太大而前端接收不了(java中的long大于js的number)而导致数据不一致,精度会丢 ...
- 案例分享:Qt国产麒麟系统某防“某显示控制项目”(多类设备自动化流程控制,数据分析整合与展示,定位图,深度图,热力图等,多应用协调管控,健壮容错)
喜报 我司承担的某防"某显示控制项目",已于近日顺利通过湖底验收. 需求 功能简介: 1.多类设备的显示.控制与管理 2.数据的分析与展示,定位图.深度图.热力图等 ...
- Kotlin 协程四 —— Flow 和 Channel 的应用
目录 一. Flow 与 Channel 的相互转换 1.1 Flow 转换为 Channel 1.1.1 ChannelFlow 1.1.2 produceIn -- 将 Flow 转换为单播式 C ...
- 制作docker方式执行Gitlab Runner所需要的镜像
背景知识 启动Gitlab Runner时,使用Gitlab提供的官方镜像gitlab/gitlab-runner:latest即可. Runner以容器的方式启动以后,根据前文我们注册到Gitlab ...
- React之父组件向子组件传值
class Parent extends React.Component{ constructor(){ super(); this.state={co:"red"} } rend ...
- [Node] nvm 安装 node 和 npm
Node JS 安装 安装 node version manager (nvm) Windows: https://github.com/coreybutler/nvm-windows/release ...