完全理解TCP/UDPHTTP长连接WebsocketSockJS/Socket.IO以及STOMP的区别和联系

Posted 流花鬼的博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了完全理解TCP/UDPHTTP长连接WebsocketSockJS/Socket.IO以及STOMP的区别和联系相关的知识,希望对你有一定的参考价值。



TCP/UDP

通过《网络工程》的学习,我们知道TCP/UDP是网络层协议,是应用层协议的基础。

对于编程的语言的学习,我们通常需要掌握Socket编程,而真正理解Socket编程TCP/UDP协议的关系,可以说是一个开发者从初级突破到中级的一个最好证明。

实际上Socket编程就是所谓的网络编程也就是基于TCP/UDP网络层协议进行编程,就拿Java和TCP来说:

  • 对于BIO,TCP编程就是

    ServerSocket/Socket

  • 对于NIO,TCP编程就是

    ServerSocketChannel/SocketChannel

  • 对于AIO,TCP编程就是

    AsynchronousServerSocketChannel/AsynchronousSocketChannel

通过对ServerSocket进行封装,我们可以实现自己的网络应用框架,例如:

名称 IO 可解析的协议
≤tomcat7 BIO HTTP等
≥tomcat8 NIO HTTP、Websocket等
Netty NIO TCP、HTTP、FTP、SMTP、Websocket等
Dubbo 基于Netty dubbo

通过对Socket进行封装,我们可以实现自己的客户端框架,例如:

名称 IO 可解析协议
OkHttp BIO HTTP、HTTPS
WebSocketClient BIO/NIO Websocket
WebClient NIO HTTP、HTTPS

Websocket

  • 通常,应用层协议都是完全基于网络层协议TCP/UDP来实现,例如HTTP、SMTP、POP3,而Websocket是同时基于HTTP与TCP来实现:

  • 先用带有 Upgrade:Websocket头 Header的特殊HTTP request来实现与服务端握手 HandShake;

  • 握手成功后,协议升级成Websocket,进行长连接通讯;

  • 整个过程可理解为: 小锤抠缝,大锤搞定

  • 为什么不使用HTTP长连接来实现即时通讯?事实上,在Websocket之前就是使用HTTP长连接这种方式,如Comet。但是它有如下弊端:

  • HTTP 1.1 规范中规定,客户端不应该与服务器端建立超过两个的 HTTP 连接, 新的连接会被阻塞。

  • 对于服务端来说,每个长连接都占有一个用户线程,在NIO或者异步编程之前,服务端开销太大。

  • 为什么不直接使用Socket编程,基于TCP直接保持长连接,实现即时通讯?

  • Socket编程针对C/S模式的,而浏览器是B/S模式,浏览器没法发起Socket请求,正因如此, W3C最后还是给出了浏览器的Socket----Websocket。


SockJS/Socket.IO

html5规范中给出了原生的Websocket API,但是并不是所有浏览器都完美支持,而当浏览器不支持Websocket时,应该自动切换成Ajax长轮询,SSE等备用解决方案。所以在实际开发中我们通常采用封装了Websocket及其备用方案的库---- SockJS(https://github.com/sockjs/sockjs-client)Socket.IO(https://github.com/socketio)

如果你使用Java做服务端,同时又恰好使用Spring Framework作为框架,那么推荐使用SockJS,因为Spring Framework本身就是SockJS推荐的Java Server实现,同时也提供了Java 的client实现。

如果你使用Node.js做服务端,那么毫无疑问你该选择 Socket.IO(https://github.com/socketio/socket.io-client),它本省就是从Node.js开始的,当然服务端也提供了 engine.io-server-java(https://github.com/socketio/engine.io-server-java)实现。甚至你可以使用 netty-socketio(https://github.com/mrniko/netty-socketio)注意:不管你使用哪一种,都必须保证客户端与服务端同时支持


STOMP

STOMP(http://stomp.github.io/)(Simple (or Streaming) Text Orientated Messaging Protocol)一个简单的面向文本/流的消息协议。STOMP提供了能够协作的报文格式,以至于STOMP客户端可以与任何STOMP消息代理(Brokers)进行通信,从而为多语言,多平台和Brokers集群提供简单且普遍的消息协作。

STOMP可用于任何可靠的双向流网络协议之上,如TCP和WebSocket。 虽然STOMP是面向文本的协议,但消息有效负载可以是文本或二进制。

STOMP是一种基于帧的协议,帧的结构是效仿HTTP报文格式,简洁明了。如下:

 
   
   
 
  1. COMMAND

  2. header1:value1

  3. header2:value2


  4. Body^@


STOMP over Websocket

STOMP over Websocket 是什么?

STOMP over Websocket 即,通过Websocket建立STOMP连接,也就是说在Websocket连接的基础上再建立 STOMP连接。

为什么要使用STOMP over Websocket?

WebSocket协议定义了两种类型的消息,文本和二进制,但它们的内容是未定义的。

如果说Socket是C/S的TCP编程,同理Websocket就是Web(B/S)的TCP编程,所以需要在客户端与服务端之间定义一个机制去协商一个子协议——更高级别的消息协议,将它使用在Websocket之上去定义每次发送消息的类别、格式和内容,等等。

子协议的使用是可选的,但无论哪种方式,客户端和服务器都需要就一些定义消息内容的协议达成一致。

于是,通常选择在Websocket协议上使用STOMP协议来定义内容格式。


实现架构

服务端:Spring Websocket/SockJS + Spring Messaging(STOMP)+RabbitMQ (也可以不使用外部Broker那么Spring application则作为Broker)JS客户端: [STOMP.js](https://github.com/jmesnil/stomp-websocket)JS客户端文档: [STOMP overWebsocket](http://jmesnil.net/stomp-websocket/doc/)Java(Android)客户端: [StompProtocolandroidViaWebsocket](https://github.com/NaikSoftware/StompProtocolAndroid)Spring支持: [SpringSTOMP](https://docs.spring.io/spring/docs/5.0.8.RELEASE/spring-framework-reference/web.html#websocket-stomp-handle-broker-relay)RabbitMQ支持: [RabbitMQSTOMP plugin](http://www.rabbitmq.com/web-stomp.html)DEMO: [《会飞的污熊---集成WebSocket实时通信》](https://github.com/yidao620c/SpringBootBucket/tree/master/springboot-websocket)如有疑问: [《SpringWebsocket+SockJS+STOMP实现即时通信——系列文章》](https://blog.csdn.net/qq_32331073/article/details/83040197)


以上是关于完全理解TCP/UDPHTTP长连接WebsocketSockJS/Socket.IO以及STOMP的区别和联系的主要内容,如果未能解决你的问题,请参考以下文章

Android websock 应用

实现单台测试机6万websocket长连接

实现单台测试机6万websocket长连接

HTTP1.1 Keep-Alive到底算不算长连接?

015_NGINX作为WebSocket Proxy的设置

websock第一次连不上window