• 网络基础协议

   

TPC/IP协议是传输层协议,主要解决数据如何在网络中传输。

HTTP是应用层协议,主要解决如何包装数据。

  关于TCP/IP和HTTP协议的关系,网络有一段比较容易理解的介绍:“我们在传输数据时,可以只使用(传输层)TCP/IP协议,但是那样的话,如果没有应用层,便无法识别数据内容,如果想要使传输的数据有意义,则必须使用到应用层协议,应用层协议有很多,比如HTTP、FTP、TELNET等,也可以自己定义应用层协议。WEB使用HTTP协议作应用层协议,以封装HTTP文本信息,然后使用TCP/IP做传输层协议将它发到网络上。”

 TCP建立连接和断开连接的过程简析:

   

  建立连接:首先Client端发送连接请求报文,Server段接受连接后回复ACK报文,并为这次连接分配资源。Client端接收到ACK报文后也向Server段发生ACK报文,并分配资源,这样TCP连接就建立了。

  中断连接:可以是Client端,也可以是Server端。假设Client端发起中断连接请求,也就是发送FIN报文。Server端接到FIN报文后,意思是说"我Client端没有数据要发给你了",但是如果你还有数据没有发送完成,则不必急着关闭Socket,可以继续发送数据。所以你先发送ACK,"告诉Client端,你的请求我收到了,但是我还没准备好,请继续你等我的消息"。这个时候Client端就进入FIN_WAIT状态,继续等待Server端的FIN报文。当Server端确定数据已发送完成,则向Client端发送FIN报文,"告诉Client端,好了,我这边数据发完了,准备好关闭连接了"。Client端收到FIN报文后,"就知道可以关闭连接了,但是他还是不相信网络,怕Server端不知道要关闭,所以发送ACK后进入TIME_WAIT状态,如果Server端没有收到ACK则可以重传。“,Server端收到ACK后,"就知道可以断开连接了"。Client端等待了2MSL后依然没有收到回复,则证明Server端已正常关闭,那好,我Client端也可以关闭连接了。Ok!

  •  Android中几种网络通信的手段

 1)针对TCP/IPSocketServerSocket

TCP/IP是一种面向连接的、可靠的协议。Socket仅仅是对TCP、UDP网络接口的封装,不涉及上层协议。TCP、UDP传输特性不同,分别适用于不同类型的应用层协议,其中TCP有连接,延时较长,能保证服务质量;UDP无连接,需要应用程序进行数据分包、延时短,效率高,数据包可能丢失或到达对端发生顺序混乱。在Socket之上可以实现这些RFC标准的应用层协议,也可以自定义实现私有的应用层协议。

2)针对UDPDatagramSocketDatagramPackage

  这里需要注意的是,考虑到Android设备通常是手持终端,IP都是随着上网进行分配的。不是固定的。因此开发也是有一点与普通互联网应用有所差异的。

  1. 对于UDP服务端,首先启动侦听服务,然后得到数据包进行处理,组后根据获得数据包进行反馈。
  2. UDP socket没有连接的概念,因此构造完成的DatagramSocket不会发出向对端的网络连接请求,在每一个发送的UDP数据包中包含目的地址和端口。因为UDP数据不会在对端进行重新组包,因此一次发送的数据长度必须加以限制

 3)针对直接URLHttpURLConnection

  apache httpclient高效稳定,但是维护成本高昂,故Android 开发团队不愿意在维护该库而是转投更为轻便的httpurlconnection;httpurlconnection比较轻便,灵活和易于扩展。

  HttpURLConnection的connect()函数,实际上只是建立了一个与服务器的tcp连接,并没有实际发送http请求。无论是post还是get,http请求实际上直到HttpURLConnection的getInputStream()这个函数里面才正式发送出去。

  在用POST方式发送URL请求时,URL请求参数的设定顺序是重中之重,对connection对象的一切配置(那一堆set函数)都必须要在connect()函数执行之前完成。而对outputStream的写操作,又必须要在inputStream的读操作之前。 这些顺序实际上是由http请求的格式决定的。如果inputStream读操作在outputStream的写操作之前,会抛出: java.net.ProtocolException: Cannot write output after reading input.......

  http请求实际上由两部分组成, 一个是http,所有关于此次http请求的配置都在http头里面定义, 一个是正文content。connect()函数会根据HttpURLConnection对象的配置值生成http头部信息,因此在调用connect函数之前,就必须把所有的配置准备好。在http头后面紧跟着的是http请求的正文,正文的内容是通过outputStream流写入的,实际上outputStream不是一个网络流,充其量是个字符串流,往里面写入的东西不会立即发送到网络,而是存在于内存缓冲区中,待outputStream流关闭时,根据输入的内容生成http正文至此,http请求的东西已经全部准备就绪。

  在getInputStream()函数调用的时候,就会把准备好的http请求正式发送到服务器了,然后返回一个输入流,用于读取服务器对于此次http请求的返回信息。由于http请求在getInputStream的时候已经发送出去了(包括http头和正文),因此在getInputStream()函数之后对connection对象进行设置(对http头的信息进行修改)或者写入outputStream(对正文进行修改)都是没有意义的了,执行这些操作会导致异常的发生。

4使用Web Service。Android可以通过开源包如jackson去支持Xmlrpc和Jsonrpc,另外也可以用Ksoap2去实现Webservice 。它是一种基于SAOP协议的远程调用标准,通过webservice可以将不同操作系统平台,不同语言,不同技术整合到一起。在Android中,第三方公司提供了基于webservice的jar包。

(5)直接使用WebView视图组件显示网页。基于WebView 进行开发,Google已经提供了一个基于chrome-lite的Web浏览器,直接就可以进行上网浏览网页。

理解Socket

  实际上socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API),通过Socket,我们才能使用TCP/IP协议。实际上,Socket跟TCP/IP协议没有必然的联系。Socket编程接口在设计的时候,就希望也能适应其他的网络协议。所以说,Socket的出现只是使得程序员更方便地使用TCP/IP协议栈而已,是对TCP/IP协议的抽象,从而形成了我们知道的一些最基本的函数接口,比如create、listen、connect、accept、send、read和write等等。网络有一段关于socket和TCP/IP协议关系的说法比较容易理 解:“TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时也要提供可供程序员做网络开发所用的接口,这就是Socket编程接口。”

理解断点续传

断点续传是HTTP 1.1协议的一部分,并不需要客户端特意去做多么复杂的事情。

只要利用了HTTP协议中的如下字段来和服务器端交互,就可以实现文件下载的断点续传:

Range:用于客户端到服务器端的请求,可通过该字段指定下载文件的某一段大小,及其单位。典型的格式如:

  • Range: bytes=0-499      下载第0-499字节范围的内容
  • Range: bytes=500-999  下载第500-999字节范围的内容
  • Range: bytes=-500       下载最后500字节的内容
  • Range: bytes=500-       下载从第500字节开始到文件结束部分的内容(这是最常用的一种格式)
  • Range: bytes=0-0,-1     下载第一以及最后一个字节的内容(这个看上去有点变态...)

Accept-Ranges:用于服务器端到客户端的应答,客户端通过该字段可以判断服务器是否支持断点续传(可选字段)。格式如下:Accept-Ranges: bytes  //表示支持以bytes为单位进行传输;  若是 none  表示不支持

Content-Ranges:用于服务器端到客户端的应答,与Accept-Ranges在同一个报文内,通过该字段指定了返回的文件资源的字节范围。格式如下:

  • Content-Ranges: bytes 0-499/1234             大小为1234的文件的第0-499字节范围的内容
  • Content-Ranges: bytes 734-1233/1234        大小为1234字节的文件的第734-结尾范围的内容

据此我们可以知道,断点续传这个功能是需要客户端和服务器端同时支持才能完成

  Android平台面向开发者提供了DownloadManager这个服务(service),可以用来完成下载,同时异步地得到下载进度的实时更新提示。该接口也部分的提供了断点续传功能:如果在下载过程中遇到网络错误,如信号中断等,DownloadManager会在网络恢复时尝试断点续传继续下载该文件。但不支持由用户发起的暂停然后断点续传。要扩展该功能也不难,只要为下载任务新增一种状态(类似paused_by_user),以及相关逻辑即可。

【附】服务端和客户端交互使用了两种方式:XML、JSON