介绍
WebSocket本质上一种计算机网络应用层的协议,用来弥补http协议在持久通信能力上的不足。 相对于HTTP这种非持久的协议来说,Websocket是一个持久化的协议 Websocket是一种在单个TCP连接上进行全双工通讯的协议,双工(duplex)是指两台通讯设备之间,允许有双向的资料传输。全双工的是指,允许两台设备间同时进行双向数据传输。这是相对于半双工来说的,半双工不能同时进行双向传输,这期间的区别相当于手机和对讲机的区别,手机在讲话的同时也能听到对方说话,对讲机只能一个说完另一个才能说。 在Websocket协议中,客户端和服务端只需要做一个握手的动作,就能形成一条通道,两者之间可以进行数据互相传送。
优点
- 较少的控制开销。在连接创建后,服务器和客户端之间交换数据时,用于协议控制的数据包头部相对较小
- 更强的实时性。由于协议是全双工的,所以服务器可以随时主动给客户端下发数据。相对于HTTP请求需要等待客户端发起请求服务端才能响应。
- 保持连接状态。与HTTP不同的是,Websocket需要先创建连接,这就使得其成为一种有状态的协议,之后通信时可以省略部分状态信息。
- 更好的二进制支持。Websocket定义了二进制帧,相对HTTP,可以更轻松地处理二进制内容。
- 可以支持扩展。Websocket定义了扩展,用户可以扩展协议、实现部分自定义的子协议。如部分浏览器支持压缩等。
- 更好的压缩效果。相对于HTTP压缩,Websocket在适当的扩展支持下,可以沿用之前内容的上下文,在传递类似的数据时,可以显著地提高压缩率。
握手
WebSocket不同于传统的Socket三次握手不同,由于WebSocket借用了HTTP协议,只需要一次握手即可创建连接。 以下信息可以在浏览器的开发者工具中的Network中查看
- 客户端发送请求
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Cache-Control: no-cache
Connection: Upgrade
Host: 8.210.193.111:21001
Origin: null
Pragma: no-cache
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Sec-WebSocket-Key: NK3v4ty5lHerm65s/Y0G/A==
Sec-WebSocket-Version: 13
Upgrade: websocket
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.131 Safari/537.36
- Connection和Upgrade:用于表明发起的是WebSocket协议请求
- Sec-WebSocket-Extensions:表示客户端想要表达的协议级的扩展
- Sec-WebSocket-Key:是一个base64编码值,有浏览器随机生成
- Sec-WebSocket-Version:表明客户端的协议版本
- 服务器回应
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: 2Hn3Z+/YRWG0UycOhCJNA4JnxOI=
- HTTP/1.1 101 Switching Protocols:表示建立好连接,并切换了TCP协议
- Connection和Upgrade:用于表明发起的是WebSocket协议请求
- Sec-WebSocket-Accept:这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。
Websocket的作用
- 不需要用HTTP轮询实现的“长连接”,每隔几秒钟向接口服务器请求新消息。需要不断的建立HTTP连接,等待服务器响应。
- HTTP的生命周期通过Request来界定,也就是一个Request 一个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
- 接口服务器不能主动推送新的消息到客户端
- HTTP还是一个无状态协议,(每次请求都需要传userId,userToken)
而webSocket建立起连接后,通过第一次的用户校验后,之后就不需要再次校验,服务端就可以主动推送消息到客户端。
WS和WSS
- ws协议:普通请求,占用与http相同的80端口;
- wss协议:基于SSL的安全传输,占用与tls相同的443端口。
实现
- java(需要java8版本)
- 添加javax.websocket jar包
- 实现 WebSocketTest.java
- 实现 PlayerManager.java
@ServerEndpoint(value = "/websocketTest/{userId}/{userName}")
public class WebSocketTest {
private String userId;
public String getUserId() {
return userId;
}
public void setUserId(String userId) {
this.userId = userId;
}
public Session getSession() {
return session;
}
public void setSession(Session session) {
this.session = session;
}
private Session session;
@OnOpen
public void onOpen(@PathParam("userId") String userId, @PathParam("userName") String userName, Session session) {
System.out.println("新连接:" + userId + " , " + userName);
this.userId = userId;
this.session = session;
PlayerManager.addPlayer(userId, this);
}
@OnClose
public void onClose() {
System.out.println("连接关闭:" + userId);
PlayerManager.removePlayerSession(userId);
}
@OnMessage
public void onMessage(String msg, Session session) throws IOException {
System.out.println("收到消息: " + msg);
if ("all".equals(msg)) {
sendAll(msg);
} else {
session.getBasicRemote().sendText(msg);
send2Player(msg, "333");
}
}
@OnError
public void onError(Session session, Throwable error) {
System.out.println("连接发送错误");
error.printStackTrace();
}
public void send2Player(String msg, String userId) throws IOException {
WebSocketTest wst = PlayerManager.getPlayerSession(userId);
if (null == wst) {
return;
}
wst.getSession().getBasicRemote().sendText(msg);
}
public void sendAll(String msg) throws IOException {
List<WebSocketTest> list = PlayerManager.getAllSession();
for (int i = 0; i < list.size(); i++) {
list.get(i).getSession().getBasicRemote().sendText(msg);
}
}
}
public class PlayerManager {
private static Map<String, WebSocketTest> playerSessionMap = new HashMap<>();
public static void addPlayer(String userId, WebSocketTest playerSession) {
if (userId == null || userId.equals("") || playerSessionMap == null) {
return;
}
playerSessionMap.put(userId, playerSession);
}
public static List<WebSocketTest> getAllSession() {
List<WebSocketTest> list = new ArrayList<>();
for (WebSocketTest wst : playerSessionMap.values()) {
list.add(wst);
}
return list;
}
public static WebSocketTest getPlayerSession(String userId) {
if (userId == null) {
return null;
}
WebSocketTest wst = null;
if (playerSessionMap.containsKey(userId)) {
wst = playerSessionMap.get(userId);
}
return wst;
}
public static void removePlayerSession(String userId) {
if (userId == null) {
return;
}
if (playerSessionMap.containsKey(userId)) {
playerSessionMap.remove(userId);
}
}
}
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<title></title>
</head>
<body>
<span>
id <input type="text" id="userId">
</span>
<br/>
<span>
昵称 <input type="text" id="userName">
</span>
<br/>
<span>
内容 <input type="text" id="msg">
</span>
<br/>
<button onclick="openSession()">连接</button>
<button onclick="send()">发送</button>
<button onclick="closeWebsocket()">关闭</button>
<div id="message"></div>
</body>
<script>
var ws;
function openSession() {
var userId = document.getElementById("userId").value;
var userName = document.getElementById("userName").value;
console.log('ws:localhost:8080/MavenTest_war_exploded/websocketTest/' + userId + '/' + userName)
ws = new WebSocket('ws:localhost:8080/MavenTest_war_exploded/websocketTest/' + userId + '/' + userName);
ws.onerror = onerror
ws.onopen = onopen
ws.onmessage = onmessage
ws.onclose = onclose
}
function onerror() {
setMessageInnerHTML("WEBSOCKET发生链接错误");
}
function onopen(ev) {
setMessageInnerHTML("WebSocket连接成功!");
}
function onmessage(ev) {
setMessageInnerHTML(ev.data);
}
function onclose() {
setMessageInnerHTML("WebSocket连接关闭");
}
window.onbeforeunload = function () {
closeWebSocket();
}
function setMessageInnerHTML(innerHtml){
document.getElementById("message").innerHTML += '收到回应:' + innerHtml + '<br />'
}
function closeWebsocket(){
ws.close();
}
function send(){
var message = document.getElementById("msg").value;
ws.send(message);
}
</script>
</html>
http和https
HTTP是一个基于TCP/IP通信协议来传递数据的协议,HTTP协议一般用于B/S架构,常用的请求方法有GET、POST、HEAD
1. HTTP与HTTPS有什么区别?
HTTP协议传输的数据都是未加密的,也就是明文的,因此使用HTTP协议传输隐私信息非常不安全,为了保证这些隐私数据能加密传输,于是网景公司设计了SSL(Secure Sockets Layer)协议用于对HTTP协议传输的数据进行加密,从而就诞生了HTTPS。简单来说,HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全。 HTTPS和HTTP的区别主要如下:
- https协议需要到ca申请证书,一般免费证书较少,因而需要一定费用。
- http是超文本传输协议,信息是明文传输,https则是具有安全性的ssl加密传输协议。
- http和https使用的是完全不同的连接方式,用的端口也不一样,前者是80,后者是443。
- http的连接很简单,是无状态的;HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,比http协议安全。
2. 客户端在使用HTTPS方式与Web服务器通信时有以下几个步骤
- 客户使用https的URL访问Web服务器,要求与Web服务器建立SSL连接。
- Web服务器收到客户端请求后,会将网站的证书信息(证书中包含公钥)传送一份给客户端。
- 客户端的浏览器与Web服务器开始协商SSL连接的安全等级,也就是信息加密的等级。
- 客户端的浏览器根据双方同意的安全等级,建立会话密钥,然后利用网站的公钥将会话密钥加密,并传送给网站。
- Web服务器利用自己的私钥解密出会话密钥。
- Web服务器利用会话密钥加密与客户端之间的通信。
3. URI和URL的区别
- HTTP使用统一资源标识符(Uniform Resource Identifiers, URI)来传输数据和建立连接。
- URI:Uniform Resource Identifier 统一资源标识符(身份证号)
- URL:Uniform Resource Location 统一资源定位符(住址)
- URI 是用来标识一个具体的资源的,我们可以通过 URI 知道一个资源是什么。
- URL 则是用来定位具体的资源的,标识了一个具体的资源位置。互联网上的每个文件都有一个唯一的URL。
参考文档:
WebSocket 是什么原理?为什么可以实现持久连接? - 知乎 java WebSocket开发入门WebSocket 浅谈WebSocket协议、WS协议和WSS协议原理及关系 十分钟搞懂HTTP和HTTPS协议?
|