第一章:引用概述 -短连接,长连接,短轮询,长轮询,流 SSE,websocket

一、短连接

这里的连接指的是 TCP 连接。一个 TCP 连接从创建到结束一共有 3 个阶段,分别为“三次握手”建立连接、客户端与服务端进行数据包传输、“四次挥手”断开连接。

客户端与服务端的每一次完整的消息交互(发请求——响应)都建立一次 TCP 连接,当这次交互完毕后就释放该 TCP 连接。这个过程就是短连接。

早期的 http 1.0 用的就是短连接。

  • 优点:简单。因为存在的连接都是正在通信的有用连接,不需要过多的管理。
  • 缺点:浪费资源,网络延迟较大。

为什么有这样的缺点呢?

通常来说,一个网页的加载是需要向服务端发送大量的资源请求的,包括 js 文件请求、css 样式文件请求、各种图片请求、加载页面数据的异步请求、还可能存在音频视频等媒体资源请求等等。这么多次的同一个客户端到同一个服务端的请求每次都要建立 TCP 就显得有点多余。

以通话为例,一次通话就是一次 TCP 连接,一个对话就是一次信息交互。我们可能每次通话只进行一个对话就挂线、下个对话再再拨一次号吗?显然不可能,因为无意义;拨号需要时间和成本,拨号次数越多,花费时间和成本就越高,会造成无意义的浪费。TCP 连接的“三次握手”和“四次挥手”即消耗时间,也浪费资源。

二、长连接

长连接是在 http 1.1 中提出并默认使用的。它最大的特点的就是 TCP 连接能够保持一段时间(超过这个时间会自动断开),不会再一次信息交互后马上断开,下一个请求会继续使用该 TCP 连接,达到 TCP 连接复用的效果。在 http 1.1 协议中,在响应头里用 “Connect : keep-alive” 来表示长连接。

  • 优点:有效复用 TCP 连接,减少网络延迟。
  • 缺点:需要对每个 TCP 连接增加管理,占用服务器的更多的内存。因为 TCP 连接能够保持一段时间,所以需要判断该 TCP 连接是否失效、是否应该释放连接;无论 TCP 连接是否正处于通信状态,只要是在有效期内的都要存储。

三、短轮询

轮询指的是客户端每隔一段时间就向服务端发送一次请求,最典型的例子是获取最新聊天消息。

短轮询指的是,在轮询的过程中客户端每发一个请求,服务端都会返回结果。例如:

1

2

3

4

5

6

7

客户端:有新消息吗?

服务端:有。

客户端:有新消息吗?

服务端:没有。

客户端:有新消息吗?

服务端:没有。

...

其实,在这种情景下,没消息也回复就显得有点冗余。假设,现在有很 10000 用户都在同一时刻进行短轮询,有新消息,服务端要进行 10000 个响应;由于并不是每一秒都会有新消息的,不如说没新消息的时间占比例更大,这时服务端也要进行 10000 个无新消息响应。这样会造成无意义的资源浪费。

四、长轮询

长轮询与短轮询的不同之处就在于,服务端在没新消息是是不会马上进行响应,而是将该请求挂起,直到有新消息时再响应,或者等到请求超时直接删除。客户端等到请求有结果(成功或失败),才发下一个请求。这样就有效解决了短轮询的问题。例如:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

客户端:有新消息吗?

服务端:有。

 

客户端:有新消息吗?

...无消息,继续等

服务端:有(出现新消息)

 

客户端:有新消息吗?

...无消息,继续等

...继续等

...超时

 

客户端:有新消息吗?

...

  • 缺点:服务器将请求挂起也是要消耗资源的,而且返回数据顺序无保证。

五、流

实现服务器推送的方法除了轮询外,还可以用 http 流。不同于轮询,流 的生命周期内只使用一个 http 连接。

客户端发一个请求,服务器保持 http 连接打开,然后周期性向浏览器发送数据。

客户端的实现代码:

1

2

3

4

5

6

7

8

9

10

11

12

13

var xhr = new XMLHttpRequest()

received = 0

xhr.onreadystatechange = function(){

if(xhr.readyState == 3){

result = xhr.responseText.substring(received) // 截取最新部分

console.log(result)

received += result.length

}else if(xhr.readyState == 4){ // 已接收完毕

console.log("Finished")

}

}

xhr.open('get', '请求 url')

xhr.send()

要说轮询是客户端向服务器催债的话,那么 http 流就是服务器向客户端分期付款。

六、SSE

SSE(Server-Sent Event,服务器发送事件)是服务器到客户端的单向连接模式,只允许服务器向客户端发送消息。

SSE 的 API 为 EventSource 对象。使用方法:

1

2

3

4

var see = new EventSource('请求 url')

sse.onopen = function(event){} // 建立连接时触发

sse.onmessage = function(event){} // 接收到新消息时触发

sse.onerror = function(event){} // 无法建立连接时触发

响应的 MIME 类型为 text/event-stream,响应格式为纯文本。每个数据项都有 data:前缀,如:

1

data: foo

默认情况下,EventSource 对象会保持与服务器的连接。如果断开会自动重连;如果想永久断开,调用 sse.close() 方法。

七、Web Socket

Web Socket 是一种全双通、双向通信的持久连接。在 js 中创建 Web Socket 后,客户端会发一个 http 请求,取得服务器响应后,建立的连接会从 http 协议变为 Web Socket 协议。未加密连接从 http:// 变为 ws://,加密连接从 https:// 变为 wss://。

Web Socket 使用自定义协议的好处是,能够在客户端和服务器之间发送更少量的数据,而不必担心 http 的字节级开销。但是,由于自定义协议的缺陷,不断有人发现这个协议存在一致性和安全性问题。

Web Socket 使用方法:

1

2

3

4

5

6

7

8

9

var ws = new WebSocket('ws://url')

ws.send('hello world')

ws.onmessage = function(e){

console.log(e.data)

}

ws.onopen = function(){}

ws.onerror = function(){}

ws.onoclose = function(){}

ws.close()

 

你可能感兴趣的:(JAVA,#,网络通信,http,websocket)