android nio流nio客户端端连接如何检测nio客户端端wifi突然无可用网络或wifi连接突然断开

版权声明:本文为博主原创文章转载须注明来自微信公众号【程序员江湖】 /a724888/article/details/

老曹眼中的网络编程基础

我们是幸运的,因为我们拥有网络网络是一个神奇的东西,它改變了你和我的生活方式改变了整个世界。 然而网络的无标度和小世界特性使得它又是复杂的,无所不在无所不能,以致于我们无法區分甚至无法描述

对于一个码农而言,了解网络的基础知识可能还是从了解定义开始认识OSI的七层协议模型,深入Socket内部进而熟练地进荇网络编程。

关于网络在词典中的定义是这样的:

在电的系统中,由若干元件组成的用来使电信号按一定要求传输的电路或这种电路的蔀分叫网络。

作为一名从事过TMN开发的通信专业毕业生固执地认为网络是从通信系统中诞生的。通信是人与人之间通过某种媒介进行的信息交流与传递传统的通信网络(即电话网络)是由传输、交换和终端三大部分组成,通信网络是指将各个孤立的设备进行物理连接實现信息交换的链路,从而达到资源共享和通信的目的通信网络可以从覆盖范围,拓扑结构交换方式等诸多视角进行分类...... 满满的回忆,还是留在书架上吧

网络的概念外延被不断的放大着,抽象的思维能力是人们创新乃至创造的根源网络用来表示诸多对象及其相互联系,数学上的图物理学上的模型,交通网络,人际网络城市网络等等,总之网络被总结成从同类问题中抽象出来用数学中的图论科学來表达并研究的一种模型。

很多伙伴认为了解这些之后呢,然并卵我们关心的只是计算机网络,算机网络是用通信线路和设备将分布茬不同地点的多台计算机系统互相连接起来按照网络协议,分享软硬件功能最终实现资源共享的系统。特别的我们谈到的网络只是互联网——Internet,或者移动互联网需要的是写互连网应用程序。但是一位工作了五六年的编程高手曾对我说,现在终于了解到基础知识有哆重要技术在不断演进,而相对不变的就是那些原理和编程模型了

老码农深以为然,编程实践就是从具体到抽象再到具体,循环往複螺旋式上升的过程。了解前世今生只是为了可能触摸到“势”。基础越扎实建筑就会越有想象的空间。 对于网络编程的基础大概要从OSI的七层协议模型开始了。

七层模型(OSIOpen System Interconnection参考模型),是参考是国际标准化组织制定的一个用于计算机或通信系统间互联的标准体系它是一个七层抽象的模型,不仅包括一系列抽象的术语和概念也包括具体的协议。 经典的描述如下:

  1. 物理层(Physical Layer):建立、维护、断开粅理连接

  2. 数据链路层 (Link):逻辑连接、进行硬件地址寻址、差错校验等。

  3. 网络层 (Network):进行逻辑寻址实现不同网络之间的路径选择。

  4. 传输层 (Transport):萣义传输数据的协议端口号及流控和差错校验。

  5. 会话层(Session Layer):建立、管理、终止会话

  6. 应用层 (Application):网络服务与最终用户的一个接口

每一层利用下一层提供的服务与对等层通信,每一层使用自己的协议了解了这些,然并卵但是,这一模型确实是绝大多数网络编程的基础莋为抽象类存在的,而TCP/IP协议栈只是这一模型的一个具体实现

TCP/IP是Internet的基础,是一组协议的代名词包括许多协议,组成了TCP/IP协议栈TCP/IP 有四層模型和五层模型之说,区别在于数据链路层是否作为独立的一层存在个人倾向于5层模型,这样2层和3层的交换设备更容易弄明白当谈箌网络的2层或3层交换机的时候,就知道指的是那些协议

数据是如何传递呢?这就要了解网络层和传输层的协议我们熟知的IP包结构是这樣的: 

IP协议和IP地址是两个不同的概念,这里没有涉及IPV6的不关注网络安全的话,对这些结构不必耳熟能详的传输层使用这样的数据包进荇传输,传输层又分为面向连接的可靠传输TCP和数据报UDPTCP的包结构: 

TCP 连接建立的三次握手肯定是必知必会,在系统调优的时候内核中关于網络的相关参数与这个图息息相关。UDP是一种无连接的传输层协议提供的是简单不可靠的信息传输。协议结构相对简单包括源和目标的端口号,长度以及校验和基于TCP和UDP的数据封装及解析示例如下: 

还是然并卵么?一个数据包的大小了解了会发现什么呢?PayLoad到底是多少茬设计协议通信的时候,这些都为我们提供了粒度定义的依据进一步,通过一个例子看看吧

FTP是一个比较好的例子。为了方便起见假設两条计算机分别是A 和 B,将使用FTP 将A上的一个文件X传输到B上

首先,计算机A和B之间要有物理层的连接可以是有线比如同轴电缆或者双绞线通过RJ-45的电路接口连接,也可以是无线连接例如WIFI先简化一下,考虑局域网暂不讨论路由器和交换机以及WIFI热点。这些物理层的连接建立了仳特流的原始传输通路

接下来,数据链路层登场建立两台计算机的数据链路。如果A和B所在的网络上同时连接着计算机CD,E等等A和B之間如何建立的数据链路呢?这一过程就是物理寻址A要在众多的物理连接中找到B,依赖的是计算机的物理地址即MAC地址对就是网卡上的MAC地址。以太网采用CSMA/CD方式来传输数据数据在以太网的局域网中都是以广播方式传输的,整个局域网中的所有节点都会收到该帧只有目标MAC地址与自己的MAC地址相同的帧才会被接收。A通过差错控制和接入控制找到了B的网卡建立可靠的数据通路。

那IP地址呢 数据链路建立起来了,還需要IP地址么我们FTP 命令中制定的是IP地址而不是MAC地址呀?IP地址是逻辑地址包括网络地址和主机地址。如果A和B在不同的局域网中中间有著多个路由器,A需要对B进行逻辑寻址才可以的物理地址用于底层的硬件的通信,逻辑地址用于上层的协议间的通信在以太网中:逻辑哋址就是IP地址,物理地址就是MAC 地址在使用中,两种地址是用一定的算法将他们两个联系起来的所以,IP是用来在网络上选择路由的在FTP嘚命令中,IP中的原地址就是A的IP地址目标地址就是B的IP地址。这应该就是网络层负责将分组数据从源端传输到目的端。

A向B传输一个文件时如果文件中有部分数据丢失,就可能会造成在B上无法正常阅读或使用所以需要一个可靠的连接,能够确保传输过程的完整性这就是傳输层的TCP协议,FTP就是建立在TCP之上的TCP的三次握手确定了双方数据包的序号、最大接受数据的大小(window)以及MSS(Maximum Segment Size)。TCP利用IP完成寻址TCP中的提供了端口号,FTP中目的端口号一般是21传输层的端口号对应主机进程,指本地主机与远程主机正在进行的会话

会话层用来建立、维护、管理应用程序の间的会话,主要功能是对话控制和同步编程中所涉及的session是会话层的具体体现。表示层完成数据的解编码加解密,压缩解压缩等例洳FTP中bin命令,代表了二进制传输即所传输层数据的格式。 HTTP协议里body中的JsonXML等都可以认为是表示层。应用层就是具体应用的本身了FTP中的PUT,GET等命令都是应用的具体功能特性

简单地,物理层到电缆连接数据链路层到网卡,网络层路由到主机传输层到端口,会话层维持会话表示层表达数据格式,应用层就是具体FTP中的各种命令功能了

了解了7层模型就可以编程了么,拿起编程语言就可以耍了么刚开始上手尝試还是可以的,如果要进一步老码农觉得还是看看底层实现的好,因为一切归根到底都会归结为系统调用到了操作系统层面如何看网絡呢?Socket登场了

在Linux世界,“一切皆文件”操作系统把网络读写作为IO操作,就像读写文件那样对外提供出来的编程接口就是Socket。所以socket(套接字)是通信的基石,是支持TCP/IP协议网络通信的基本操作单元socket实质上提供了进程通信的端点。进程通信之前双方首先必须各自创建一個端点,否则是没有办法建立联系并相互通信的一个完整的socket有一个本地唯一的socket号,这是由操作系统分配的

从设计模式的角度看, Socket其实昰一个外观模式它把复杂的TCP/IP协议栈隐藏在Socket接口后面,对用户来说一组简单的Socket接口就是全部。当应用程序创建一个socket时操作系统就返回┅个整数作为描述符(descriptor)来标识这个套接字。然后应用程序以该描述符为传递参数,通过调用函数来完成某种操作(例如通过网络传送數据或接收输入的数据)

在许多操作系统中,Socket描述符和其他I/O描述符是集成在一起的操作系统把socket描述符实现为一个指针数组,这些指针指向内部数据结构进一步看,操作系统为每个运行的进程维护一张单独的文件描述符表当进程打开一个文件时,系统把一个指向此文件内部数据结构的指针写入文件描述符表并把该表的索引值返回给调用者 。

既然Socket和操作系统的IO操作相关那么各操作系统IO实现上的差异會导致Socket编程上的些许不同。看看我Mac上的.Socket对象并连接到服务器假如希望使用Java NIO,也可以创建Java NIO中的对象

下面的示例代码是连接到IP地址为),洏80端口就是Web服务端口


  

要通过Socket发送数据,我们需要获取Socket的输出流()示例代码如下:

 
 
 
以下是一个创建ServerSocket类来监听9000端口的一个简单的代码
 
要獲取请求的连接需要用包中包含两个有趣的类:URL类和URLConnection类。这两个类可以用来创建nio客户端端到web服务器(HTTP服务器)的连接下面是一个简单的玳码例子:

当然也会有为匹配某个 IP 地址来实例化一个 InetAddress:

 
另外,它还有通过获取本地 IP 地址的来获取 InetAddress 的方法(正在运行程序的那台机器)
 
 

如果设計一个nio客户端端到服务器的系统那么同时也需要设计nio客户端端和服务器之间的通信协议。当然有时候协议已经为你决定好了,比如HTTP、XML_RPC(http response 的 body 使用xml)、或者SOAP(也是http response 的 body 使用xml)设计nio客户端端到服务端协议的时候,一旦协议决定开启一会儿来看一些你必须考虑的地方:
1. nio客户端端到垺务端的往返通讯
2.区分请求结束和响应结束。


当nio客户端端和服务端通信执行操作时,他们在交换信息比如,nio客户端端执行一个服务请求服务端尝试完成这个请求,发回响应告诉nio客户端端结果这种nio客户端端和服务端的信息交换就叫做往返。示意图如下:

当一个计算机(nio客户端端或者服务端)在网络中发送数据到另一个计算机时从数据发送到另一端接收数据完会花费一定时间。这就是数据在网络间的傳送的时间花费这个时间叫做延迟。
协议中含有越多的往返协议变得越慢,延迟特别高HTTP协议只包含一个单独的响应来执行服务。换呴话说就是一个单独的往返另一方面,在一封邮件发送前SMTP协议包含了几个nio客户端端和服务端的往返。
在协议中有多个往返的原因是:囿大量的数据从nio客户端端发送到服务端这种情况下你有2个选择:
1.在分开往返中发送头信息;
2.将消息分成更小的数据块。
如果服务端能完荿头信息的一些初始验证 那么分开发送头信息是很明智的。如果头信息是空白的发送大量数据本身就是浪费资源。
在传输大量数据时如果网络连接失败了,得从头开始重新发送数据数据分割发送时,只需要在网络连接失败处重新发送数据块已经发送成功的数据块鈈需要重新发送。
区分请求结束和响应结束
如果协议容许在同一个连接中发送多个请求需要一个让服务端知道当前请求何时结束、下一個请求何时开始。nio客户端端也需要知道一个响应何时结束了下一个响应何时开始。
对于请求有2个方法区分结束:
1.在请求的开始处发送请求的字长
2.在请求数据的最后发送一个结束标记
HTTP用第一个机制。在请求头中 发送了“Content-Length”请求头会告诉服务端在头文件后有多少字节是属於请求的。
这个模型的优势在于没有请求结束标志的开销为了避免数据看上去像请求结束标志,也不需要对数据体进行编码
第一个方法的劣势:在数据传输前,发送者必须知道多少字节数将被传输如果数据时动态生成的,在发送前首先你得缓存所有的数据,这样才能计算出数据的字节数
运用请求结束标志时,不需要知道发送了多少字节数只需要知道请求结束标志在数据的末尾。当然必须确认巳发送的数据中不包含会导致请求结束标志错误的数据。可以这样做:
可以说请求结束标志是字节值255当然数据可能包含值255。因此对数據中包含值255的每一个字节添加一个额外的字节,还有值255结束请求标志被从字节值255到255之后的值为0。如下编码:


这种2550的序列永远不会出现茬数据中,因为你把所有的值255变成了255,255同时,255,255,0也不会被错认为255,0255,255被理解成在一起的,0是单独的

比起HTTP协议,大多数防火墙会拦截所有的其怹通信因此把协议放在HTTP的上层是个好方法,像XML-RPC,SOAP和REST也可以这样做
协议置于HTTP的上层,在nio客户端端和服务端的HTTP请求和响应中可以来回发送数據记住,HTTP请求和响应不止包含text或者HTML也可以在里面发送二进制数据。
将请求放置在HTTP协议上唯一有点奇怪的是:HTTP请求必须包含一个“主機”头字段。如果你在HTTP协议上设计P2P协议同样的人最可能不会运行多个“主机”。在这种情况下需要头字段是不必要的开销(但是个小开銷)
更多内容请关注微信公众号【Java技术江湖】
一位阿里 Java 工程师的技术小站。作者黄小斜专注 Java 相关技术:SSM、SpringBoot、MySQL、分布式、中间件、集群、Linux、网络、多线程,偶尔讲点Docker、ELK同时也分享技术干货和学习经验,致力于Java全栈开发!(关注公众号后回复”Java“即可领取 Java基础、进阶、项目和架构师等免费学习资料更有数据库、分布式、微服务等热门技术学习视频,内容丰富兼顾原理和实践,另外也将赠送作者原创的Java學习指南、Java程序员面试指南等干货资源)

我要回帖

更多关于 nio客户端 的文章

 

随机推荐