在项目开发过程中,不免要与后台进行交互,这时候我们就需要研究一下通信,做一个选择。
Http通信采用UDP,传输过但可能会丢数据,一般我们用来传递字符串或者下载图片时采用,轻量级。
Socket通信采用TCP,安全但慢,一般用来做大型项目中注册、定单信息的传输操作,每个Client都要跟Server 建立连接,所以这个要考虑到用户访问级别,一般百万级,航空公司就是千万级。
下面讲一个TCP与UDP之间的具体差别:
简而言之,TCP与UDP之间的区别在于,TCP传输数据安全但速度慢,UDP传输容易丢包但速度快。一般银行要采取TP协议,IM要使用UDP协议。
首先我们来看一下什么是TCP和UDP。
什么是TCP?
TCP:Transmission Control Protocol 传输控制协议TCP是一种面向连接(连接导向)的、可靠的、基于字节流的运输层(Transport layer)通信协议,由IETF的RFC 793说明(specified)。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能。应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个字节一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算校验和。
首先,TCP建立连接之后,通信双方都同时可以进行数据的传输,其次,他是全双工的;在保证可靠性上,采用超时重传和捎带确认机制。
在流量控制上,采用滑动窗口协议[1],协议中规定,对于窗口内未经确认的分组需要重传。
在拥塞控制上,采用慢启动算法。
什么是UDP?
UDP 是User Datagram Protocol的简称, 中文名是用户数据包协议,是 OSI 参考模型中一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。它是IETF RFC 768是UDP的正式规范。在网络中它与TCP协议一样用于处理数据包。在OSI模型中,在第四层——传输层,处于IP协议的上一层。UDP有不提供数据报分组、组装和不能对数据包的排序的缺点,也就是说,当报文发送之后,是无法得知其是否安全完整到达的。 UDP用来支持那些需要在计算机之间传输数据的网络应用。包括网络视频会议系统在内的众多的客户/服务器模式的网络应用都需要使用UDP协议。UDP协议从问世至今已经被使用了很多年,虽然其最初的光彩已经被一些类似协议所掩盖,但是即使是在今天,UDP仍然不失为一项非常实用和可行的网络传输层协议。
与所熟知的TCP(传输控制协议)协议一样,UDP协议直接位于IP(网际协议)协议的顶层。根据OSI(开放系统互连)参考模型,UDP和TCP都属于传输层协议。
UDP协议的主要作用是将网络数据流量压缩成数据报的形式。一个典型的数据报就是一个二进制数据的传输单位。每一个数据报的前8个字节用来包含报头信息,剩余字节则用来包含具体的传输数据。
TCP和UDP在android中的使用和在Java里是完全一样的。
首先我们看看TCP连接,下图为TCP连接的一个示意图:
是不是很好理解,这里就不多说了,直接看代码吧!实践出真知。
TCP服务器端代码:
- try {
- Boolean endFlag = false;
- ServerSocket ss = new ServerSocket(12345);
- while (!endFlag) {
- // 等待客户端连接
- Socket s = ss.accept();
- BufferedReader input = new BufferedReader(newInputStreamReader(s.getInputStream()));
- //注意第二个参数据为true将会自动flush,否则需要需要手动操作output.flush()
- PrintWriter output = newPrintWriter(s.getOutputStream(),true);
- String message = input.readLine();
- Log.d("Tcp Demo", "message from Client:"+message);
- output.println("message received!");
- //output.flush();
- if("shutDown".equals(message)){
- endFlag=true;
- }
- s.close();
- }
- ss.close();
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
TCP客户端代码:
- try {
- Socket s = new Socket("localhost", 12345);
- // outgoing stream redirect to socket
- OutputStream out = s.getOutputStream();
- // 注意第二个参数据为true将会自动flush,否则需要需要手动操作out.flush()
- PrintWriter output = new PrintWriter(out, true);
- output.println("Hello IdeasAndroid!");
- BufferedReader input = new BufferedReader(newInputStreamReader(s
- .getInputStream()));
- // read line(s)
- String message = input.readLine();
- Log.d("Tcp Demo", "message From Server:" + message);
- s.close();
- } catch (UnknownHostException e) {
- e.printStackTrace();
- } catch (IOException e) {
- e.printStackTrace();
- }
下面我们看看UDP:
UDP传输原理
UDP服务器端代码:
- // UDP服务器监听的端口
- Integer port = 12345;
- // 接收的字节大小,客户端发送的数据不能超过这个大小
- byte[] message = new byte[1024];
- try {
- // 建立Socket连接
- DatagramSocket datagramSocket = new DatagramSocket(port);
- DatagramPacket datagramPacket = new DatagramPacket(message,
- message.length);
- try {
- while (true) {
- // 准备接收数据
- datagramSocket.receive(datagramPacket);
- Log.d("UDP Demo", datagramPacket.getAddress()
- .getHostAddress().toString()
- + ":" + new String(datagramPacket.getData()));
- }
- } catch (IOException e) {
- e.printStackTrace();
- }
- } catch (SocketException e) {
- e.printStackTrace();
- }
UDP客户端代码:
- public static void send(String message) {
- message = (message == null ? "Hello IdeasAndroid!" : message);
- int server_port = 12345;
- DatagramSocket s = null;
- try {
- s = new DatagramSocket();
- } catch (SocketException e) {
- e.printStackTrace();
- }
- InetAddress local = null;
- try {
- // 换成服务器端IP
- local = InetAddress.getByName("localhost");
- } catch (UnknownHostException e) {
- e.printStackTrace();
- }
- int msg_length = message.length();
- byte[] messagemessageByte = message.getBytes();
- DatagramPacket p = new DatagramPacket(messageByte, msg_length, local,
- server_port);
- try {
- s.send(p);
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
参考资料51CTO:http://mobile.51cto.com/android-224076.htm广通软件十多年来耕耘于运维管理软件研发和服务咨询,面向数据中心、互联网、物联网三个领域提供整合化的运维工具和服务。本文作者祝恩良,N次元生物,现任广通软件高级前端开发工程师。今天将以实战角度谈一谈WebSocket的特点与应用。
WebSocket是一个独立的基于TCP的协议,是HTML5新出的一个协议,跟我们认识的HTTP协议两者之间具有一定的交集,webSocket其实是借助了HTTP这个跳板,档次也杠杠的,能进行全双工通讯(全双工:允许两台设备同时进行双向资料传输)。它和HTTP唯一的关系就是它的握手请求作为一个升级请求(Upgrade request),经由HTTP服务器解析。
在我们熟知的Http version 1.0 和 version 1.1,升级版本中包含了keep-alive(Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后继请求时,Keep-Alive功能避免了建立或者重新建立连接。但是保持链接中,暂停通讯期间不会释放资源,比较浪费服务器资源。)。webSocket其实也囊括了这个概念,虽然实现并不是如此,简单的来说就HTTP协议上的一种补充。
协议
在此我们要来讲一个早就存在的概念,持久化的协议,也是webSocket的一个特征,当然这个也是相对于我们的HTTP协议来说的。
HTTP协议请求:
HTTP 1.0: 一个request 一个response 一次HTTP链接这样就算是结束了。
HTTP 1.1:在1.0版本有了改进,加入了一个Keep-Alive,在一次HTTP链接中,我可以发送多个request,接收多个response,但是一个request 只能对应一个response。而且这个response,是被动发起的。
webSocket是基于HTTP协议,
小明:报告老师,你明明说是基于TCP协议的来着,真善变。
老师:别说话,HTTP协议也是基于TCP协议的好不,我这里主要是想表达,webSocket借用了HTTP协议来完成一次握手升级请求,understand?
GET /chat HTTP/1.1
Host: xxxx.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: XXXXXX
Sec-WebSocket-Protocol: XXXX
Sec-WebSocket-Version: X
Origin:http://xxxx.com
以上内容就是一次webSocket的握手升级协议请求。
有两个参数:
Upgrade:webSocket
Connection:Upgrade
告诉服务器(Ngnix)接线员:attention please!爷发起的是webSocket协议,快帮我找一个对应的客服,不是那个蹩脚的HTTP客服。
Sec-WebSocket-Key: XXXXX
Sec-WebSocket-Protocol: A, B
Sec-WebSocket-Version: X
首先,Sec-WebSocket-Key 是一个Base64 encode的值,这个是浏览器随机生成的,旨在验证服务器给出的服务是否合格。简单的理解:别忽悠我,我要验证你是不是webSocket客服。
然后,Sec_WebSocket-Protocol 是一个用户定义的字符串,用来区分同URL下,不同的服务所需要的子协议(客户端支持的子协议列表)。简单理解:我点的服务是这个,别搞错了。
最后,Sec-WebSocket-Version 是告诉服务器所使用的Websocket版本:服务员,我要的是小学生,不是大学生噢_
服务员:客官,你的要求,我们都能满足你哟,(^_^)。
然后服务器会返回下列东西,表示已经接受到请求,成功建立Websocket啦!
HTTP/1.1101Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: XXXX
Sec-WebSocket-Protocol: B
返回的这些内容,就表示服务端升级
这部分就是HTTP最后负责的内容了,此后跟HTTP毫无关系。上述内容中:
Upgrade:webSocket
Connection:Upgrade
告诉客户端,服务端已经成功升级成webSocket协议了。
Sec-WebSocket-Accept: XXXX
这段内容是经过服务确认之后,根据客户端生成Sec-WebSocket-Key生成的值;简单理解,服务端:来,你个死傲娇,给你看我的ID info。
Sec-WebSocket-Protocol表示服务端从客户端提供的协议列表中,提供自身支持哪个(B)。
接下去的事,表示跟那个蹩脚的HTTP木有,完全木有,真的木有再有关系了,webSocket客服完全承包后续服务内容。
WebSocket的作用
在讲webSocket之前,请允许老夫再BB一会。让我们来脑补一会 long pull 和 ajax轮询吧
ajax轮询
ajax的原理非常简单,就是定时器,每隔一会发起一个请求,轮询服务端是否有新的信息。
场景大致是这样的:
客户:我的快递到了没呀?(request)
客服:你好,你是?没有(response)
客户:我的快递到了没呀?
客服:你好,你是?没有..
客户:我的快递到了没呀?
客服:你好,你是?没有,真没有
客户:我的快递到了没呀?
客服:你好,你是?