网站合同建设模板,wordpress管理员密码忘记,天津建设工程信息网专家库官网,公司托管一、WebSocket 原理
WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术#xff0c;属于应用层协议。它基于TCP传输协议#xff0c;并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手#xff0c;两者之间就直接可以创建持久性的连接#xff0c; 并…一、WebSocket 原理
WebSocket是HTML5提供的一种浏览器与服务器进行全双工通讯的网络技术属于应用层协议。它基于TCP传输协议并复用HTTP的握手通道。浏览器和服务器只需要完成一次握手两者之间就直接可以创建持久性的连接 并进行双向数据传输。
WebSocket 的出现就解决了半双工通信的弊端。它最大的特点是服务器可以向客户端主动推动消息客户端也可以主动向服务器推送消息。 WebSocket 特点的如下 ● 支持双向通信实时性更强 ● 可以发送文本也可以发送二进制数据 ● 建立在TCP协议之上服务端的实现比较容易 ● 数据格式比较轻量性能开销小通信高效 ● 没有同源限制客户端可以与任意服务器通信 ● 协议标识符是ws如果加密则为wss服务器网址就是 URL ● 与 HTTP 协议有着良好的兼容性。默认端口也是80和443并且握手阶段采用 HTTP 协议因此握手时不容易屏蔽能通过各种 HTTP 代理服务器。
二、WebSocket 握手
WebSocket 服务端使用标准 TCP 套接字监听进入的连接。下文假定服务端监听 http://example.com 的 8000 端口响应 http://example.com/chat 上的 GET 请求。
握手是 WebSocket 中 “Web”。它是从 HTTP 到 WebSocket 的桥梁。在握手过程中协商连接的细节并且如果行为不合法那么任何一方都可以在完成前退出。服务端必须仔细理解客户端的所有要求否则可能出现安全问题。
2.1 客户端握手请求
客户端通过联系服务端请求 WebSocket 连接的方式发起 WebSocket 握手流程。客户端发送带有如下请求头的标准 HTTP 请求HTTP 版本必须是 1.1 或更高并且请求方法必须是 GET
GET /chat HTTP/1.1
Host: example.com:8000
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ
Sec-WebSocket-Version: 13在这里客户端可以请求扩展和/或子协议。此外也可以使用常见的请求头比如 User-Agent、Referer、Cookie 或者身份验证请求头。这些请求头与 WebSocket 没有直接关联。
如果存在不合法的请求头那么服务端应该发送 400 响应“Bad Request”并且立即关闭套接字。通常情况下服务端可以在 HTTP 响应体中提供握手失败的原因 。如果服务端不支持该版本的 WebSocket那么它应该发送包含它支持的版本的 Sec-WebSocket-Version 头。在上面的示例中它指示 WebSocket 协议的版本为 13。
在请求头中最值得关注的是 Sec-WebSocket-Key。接下来将讲述它。
2.2 服务端握手响应
当服务端收到握手请求时将发送一个特殊响应该响应表明协议将从 HTTP 变更为 WebSocket。
该响应头大致如下记住每个响应头行以 \r\n 结尾在最后一行的后面添加额外的 \r\n以说明响应头结束
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbKxOo此外服务端可以在这里对扩展/子协议请求做出选择。Sec-WebSocket-Accept响应头很重要服务端必须通过客户端发送的Sec-WebSocket-Key请求头生成它。具体的方式是将客户端的Sec-WebSocket-Key与字符串258EAFA5-E914-47DA-95CA-C5AB0DC85B11“魔法字符串”连接在一起然后对结果进行 SHA-1 哈希运算最后返回哈希值的 Base64 编码。
因此如果 Key 为dGhlIHNhbXBsZSBub25jZQ“那么Sec-WebSocket-Accept响应头的值是s3pPLMBiTxaQ9kYGzzhZRbKxOo”。服务端发送这些响应头后握手完成可以开始交换数据。
下面的 Python 代码根据Sec-WebSocket-Key请求头生成Sec-WebSocket-Accept响应头的值
import typing
from hashlib import sha1
import base64SEC_WS_MAGIC_STRING: bytes b258EAFA5-E914-47DA-95CA-C5AB0DC85B11def get_sec_ws_accept(sec_ws_key: typing.Union[bytes, str]) - bytes:if isinstance(sec_ws_key, str):sec_ws_key sec_ws_key.encode()return base64.b64encode(sha1(sec_ws_key SEC_WS_MAGIC_STRING).digest())if __name__ __main__:assert get_sec_ws_accept(bdGhlIHNhbXBsZSBub25jZQ) bs3pPLMBiTxaQ9kYGzzhZRbK三、数据帧Data Framing
3.1 概览
在 WebSocket 协议中使用一系列帧传输数据。为避免混淆网络中间人比如拦截代理以及出于安全考虑客户端必须对发送给服务端的所有帧进行掩码Mask处理。注意无论 WebSocket 协议是否运行在 TLS 上都需要进行掩码处理。服务端在收到未进行掩码处理的帧时必须关闭连接。在这种情况下服务端可以发送状态码为 1002协议错误的关闭帧。服务端不得对发送给客户端的任何帧进行掩码处理。如果客户端检测到掩码帧那么必须关闭连接。在这种情况下可以使用状态码 1002协议错误。
基础帧协议定义了一种帧类型包括操作码Opcode、有效载荷长度以及“扩展数据”和“应用数据”的指定位置它们一起定义“有效载荷数据”。一些位和操作码被保留以供未来扩展协议。
在握手完成后端点被发送关闭帧前客户端和服务端可以随时传输数据帧。
3.2 基础帧协议
帧的格式如下图所示
FIN1 比特
表示该帧是消息中的最后一个分片。第一个分片也可能是最后一个分片。
RSV1、RSV2、RSV3每个 1 比特
除非协商了定义非零值含义的扩展否则必须为 0。如果收到非零值并且没有协商的扩展定义该非零值的含义那么接收端点必须使该 WebSocket 连接失败。
操作码4 比特
定义对“有效载荷数据”的解释。如果收到未知操作码那么接收端点必须使该 WebSocket 连接失败。定义的值如下
%x0 表示延续帧 %x1 表示文本帧 %x2 表示二进制帧 %x3-7 为将来的非控制帧预留 %x8 表示连接关闭 %x9 表示 PING %xA 表示 PONG %xB-F 为将来的控制帧保留 掩码1 比特
定义“有效载荷数据”是否被掩码处理。如果设置为 1那么掩码键出现在 Masking-key 中它用于解除“有效载荷数据”的掩码。从客户端发送到服务器的所有帧都将此位设置为 1。
有效载荷长度7 比特716 比特或 764 比特
“有效载荷数据”的长度单位是字节如果设置为 0-125那么它是有效载荷长度。如果设置为 126那么接下来的 2 个字节被解释为 16 位无符号整数是有效载荷长度。如果设置为 127那么接下来的 8 个字节被解释为 64 位无符号整数最高有效位必须为 0是有效载荷长度。多字节长度量使用网络字节序表示。注意在所有情况下必须使用最小字节数编码长度比如124 字节长的字符串的长度不能编码为序列 126, 0, 124。有效载荷的长度是“扩展数据”的长度 “应用数据”的长度。“扩展数据”的长度可能为 0在这种情况下有效载荷长度是“应用数据”的长度。
掩码键0 或 4 字节
从客户端发送到服务端的所有帧必须通过包含在帧里的 32 位数值进行掩码处理。如果掩码位为 1那么该字段存在如果掩码位为 0那么该字段不存在。
有效载荷数据(xy) 字节
“有效载荷数据”被定义为将 “扩展数据” 与 “应用数据” 连接在一起。
扩展数据x 字节
除非已经协商了扩展否则“扩展数据”为 0 字节。所有扩展必须指定扩展数据的长度或者如何计算该长度并且在开始握手期间必须协商扩展的使用方式。如果存在那么“扩展数据”包含在总有效载荷长度中。
应用数据y 字节
任意“应用数据”占用帧中“扩展数据”后面的剩余部分。“应用数据”的长度等于有效载荷长度减去“扩展数据”的长度。
3.3 消息分片Message Fragmentation FIN 和 Opcode 字段共同协作发送被拆分成单独帧的消息。这被称为消息分片。分片仅适用于 Opcode 0x0 到 0x2 的情况。
Opcode 说明帧的用途。如果为 0x1那么有效载荷是文本。如果为 0x2那么有效载荷是二进制数据。如果为 0x0那么该帧是延续帧这意味着服务端应该将该帧的有效载荷连接到其从该客户端收到的最后一个帧。在下面的草图中服务端对发送文本消息的客户端做出响应。第一条消息以单个帧发送而第二条消息用三个帧发送。下图仅显示客户端的 FIN 和 Opcode 细节
Client: FIN1, opcode0x1, msghello
Server: (process complete message immediately) Hi.
Client: FIN0, opcode0x1, msgand a
Server: (listening, new message containing text started)
Client: FIN0, opcode0x0, msghappy new
Server: (listening, payload concatenated to previous message)
Client: FIN1, opcode0x0, msgyear!
Server: (process complete message) Happy new year to you too!注意第一个帧包含整个消息FIN1并且opcode!0x0因此服务端可以按需处理或响应。客户端发送的第二个帧的有效载荷是文本opcode0x1但整个消息尚未到达FIN0。该消息的所有剩余部分使用延续帧opcode0x0发送并且消息的最后一帧用FIN1标记。
四、Websocket的使用
4.1 客户端开发示例
const ws new WebSocket(ws://localhost:8080/ws/zhangsan);
ws.onmessage messageEvent {console.log(onmessage: , messageEvent.data)
}
ws.onopen messageEvent {console.log(onopen: , messageEvent)
}
ws.onclose messageEvent {console.log(onclose: , messageEvent)
}
ws.onerror messageEvent {console.log(onerror: , messageEvent)
}// 发送消息
ws.send(hello world~) 4.2 服务端开发示例
4.2.1 J2EE的websocket
下面的示例是用javaee的接口来进行开发而不是用springboot提供的实现 依赖引入
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId
/dependency
配置类
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.socket.server.standard.ServerEndpointExporter;Configuration
public class WebSocketConfig {Beanpublic ServerEndpointExporter serverEndpointExporter(){return new ServerEndpointExporter();}
}
服务端代码
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;Slf4j
Component
ServerEndpoint(/ws/{userName})
public class MyServerEndpoint {public void sendMessage(Session session, String message) throws IOException {log.info(准备向客户端程序{}发送消息:{}, session.getId(), message);session.getBasicRemote().sendText(message);}OnMessagepublic void onMessage(PathParam(userName) String userName,String message, Session session) {log.info(收到来自客户端{}的消息! sessionId: {}, 消息{}, userName, session.getId(), message);try {sendMessage(session, message);} catch (IOException e) {log.error(消息发送失败!, e);}}OnOpenpublic void onOpen(PathParam(userName) String userName, Session session) {log.info(客户端程序{}建立连接成功! sessionId:{}, userName, session.getId());}OnClosepublic void onClose(PathParam(userName) String userName, Session session, CloseReason closeReason) {log.info(客户端{}断开连接原因{}, userName, closeReason);}OnErrorpublic void onError(Session session, Throwable throwable) {log.info(连接{}发生错误!, session.getId());throwable.printStackTrace();}
}
4.2.2 SpringFramework提供的websocket
依赖引入
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId
/dependency
配置类
Slf4j
Configuration
EnableWebSocket
public class SockConfig implements WebSocketConfigurer {Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(echoWebSocketHandler(), /ws/{userName}).setAllowedOriginPatterns(*).setHandshakeHandler(new DefaultHandshakeHandler()).addInterceptors(new HttpSessionHandshakeInterceptor() {Overridepublic boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, MapString, Object attributes) throws Exception {// 认证等操作。。。return true;}});}public WebSocketHandler echoWebSocketHandler() {return new TextWebSocketHandler() {Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {// 收到的信息String requestMsg message.getPayload();System.out.println(服务器收到 requestMsg);// 组织响应信息String responseMsg 服务器返回: requestMsg;System.out.println(responseMsg);TextMessage respMsg new TextMessage(responseMsg.getBytes(StandardCharsets.UTF_8));// 返回给客户端session.sendMessage(respMsg);}};}
}
推荐使用springBoot提供的包来进行开发封装了很多功能简化了开发 文章转载自: http://www.morning.lqjlg.cn.gov.cn.lqjlg.cn http://www.morning.kgfsz.cn.gov.cn.kgfsz.cn http://www.morning.cfcpb.cn.gov.cn.cfcpb.cn http://www.morning.qmqgx.cn.gov.cn.qmqgx.cn http://www.morning.gbwfx.cn.gov.cn.gbwfx.cn http://www.morning.txtzr.cn.gov.cn.txtzr.cn http://www.morning.wfjrl.cn.gov.cn.wfjrl.cn http://www.morning.gfjgq.cn.gov.cn.gfjgq.cn http://www.morning.mdmc.cn.gov.cn.mdmc.cn http://www.morning.yxbdl.cn.gov.cn.yxbdl.cn http://www.morning.ydmml.cn.gov.cn.ydmml.cn http://www.morning.yltyr.cn.gov.cn.yltyr.cn http://www.morning.sgtq.cn.gov.cn.sgtq.cn http://www.morning.bchgl.cn.gov.cn.bchgl.cn http://www.morning.rbsxf.cn.gov.cn.rbsxf.cn http://www.morning.fllfc.cn.gov.cn.fllfc.cn http://www.morning.ffksr.cn.gov.cn.ffksr.cn http://www.morning.nlzpj.cn.gov.cn.nlzpj.cn http://www.morning.hsflq.cn.gov.cn.hsflq.cn http://www.morning.wztnh.cn.gov.cn.wztnh.cn http://www.morning.mdgpp.cn.gov.cn.mdgpp.cn http://www.morning.mfbzr.cn.gov.cn.mfbzr.cn http://www.morning.lsxabc.com.gov.cn.lsxabc.com http://www.morning.zxqyd.cn.gov.cn.zxqyd.cn http://www.morning.mdpkf.cn.gov.cn.mdpkf.cn http://www.morning.kyzja.com.gov.cn.kyzja.com http://www.morning.grxsc.cn.gov.cn.grxsc.cn http://www.morning.rmqlf.cn.gov.cn.rmqlf.cn http://www.morning.kxsnp.cn.gov.cn.kxsnp.cn http://www.morning.lcbgf.cn.gov.cn.lcbgf.cn http://www.morning.tdhxp.cn.gov.cn.tdhxp.cn http://www.morning.tkqzr.cn.gov.cn.tkqzr.cn http://www.morning.xrftt.cn.gov.cn.xrftt.cn http://www.morning.lpsjs.com.gov.cn.lpsjs.com http://www.morning.chongzhanggui.cn.gov.cn.chongzhanggui.cn http://www.morning.brscd.cn.gov.cn.brscd.cn http://www.morning.qznkn.cn.gov.cn.qznkn.cn http://www.morning.ydxg.cn.gov.cn.ydxg.cn http://www.morning.lrnfn.cn.gov.cn.lrnfn.cn http://www.morning.yptwn.cn.gov.cn.yptwn.cn http://www.morning.pmsl.cn.gov.cn.pmsl.cn http://www.morning.plfy.cn.gov.cn.plfy.cn http://www.morning.tmrjb.cn.gov.cn.tmrjb.cn http://www.morning.rmxk.cn.gov.cn.rmxk.cn http://www.morning.dmlsk.cn.gov.cn.dmlsk.cn http://www.morning.tdscl.cn.gov.cn.tdscl.cn http://www.morning.ylqrc.cn.gov.cn.ylqrc.cn http://www.morning.gcfrt.cn.gov.cn.gcfrt.cn http://www.morning.ktyww.cn.gov.cn.ktyww.cn http://www.morning.sglcg.cn.gov.cn.sglcg.cn http://www.morning.hhxwr.cn.gov.cn.hhxwr.cn http://www.morning.yjprj.cn.gov.cn.yjprj.cn http://www.morning.dhqyh.cn.gov.cn.dhqyh.cn http://www.morning.stprd.cn.gov.cn.stprd.cn http://www.morning.zybdj.cn.gov.cn.zybdj.cn http://www.morning.tqdlk.cn.gov.cn.tqdlk.cn http://www.morning.uytae.cn.gov.cn.uytae.cn http://www.morning.knzdt.cn.gov.cn.knzdt.cn http://www.morning.hhkzl.cn.gov.cn.hhkzl.cn http://www.morning.xxsrm.cn.gov.cn.xxsrm.cn http://www.morning.lxcwh.cn.gov.cn.lxcwh.cn http://www.morning.tkjh.cn.gov.cn.tkjh.cn http://www.morning.msbpb.cn.gov.cn.msbpb.cn http://www.morning.kgcss.cn.gov.cn.kgcss.cn http://www.morning.qhczg.cn.gov.cn.qhczg.cn http://www.morning.jxpwr.cn.gov.cn.jxpwr.cn http://www.morning.hrtfz.cn.gov.cn.hrtfz.cn http://www.morning.gl-group.cn.gov.cn.gl-group.cn http://www.morning.zrkws.cn.gov.cn.zrkws.cn http://www.morning.dpzcc.cn.gov.cn.dpzcc.cn http://www.morning.rscrj.cn.gov.cn.rscrj.cn http://www.morning.ldcrh.cn.gov.cn.ldcrh.cn http://www.morning.bxyzr.cn.gov.cn.bxyzr.cn http://www.morning.qrwjb.cn.gov.cn.qrwjb.cn http://www.morning.jmmz.cn.gov.cn.jmmz.cn http://www.morning.tbqxh.cn.gov.cn.tbqxh.cn http://www.morning.yfqhc.cn.gov.cn.yfqhc.cn http://www.morning.ryysc.cn.gov.cn.ryysc.cn http://www.morning.phxdc.cn.gov.cn.phxdc.cn http://www.morning.gkjnz.cn.gov.cn.gkjnz.cn