WebSocket原理及模板(附java源码)
原理⽅⾯,参考其他⼤⽜博客。
参考链接:
⽬录
先说⼀下Http
HTTP有1.1和1.0之说,也就是所谓的keep-alive,把多个HTTP请求合并为⼀个,但是Websocket其实是⼀个新协议,跟HTTP协议基本没有关系,只是为了兼容现有浏览器的握⼿规范⽽已,也就是说它是HTTP协议上的⼀种补充可以通过这样⼀张图理解
有交集,但是并不是全部。
另外Html5是指的⼀系列新的API,或者说新规范,新技术。Http协议本⾝只有1.0和1.1,⽽且跟Html本⾝没有直接关系。。
通俗来说,你可以⽤HTTP协议传输⾮Html数据,就是这样=。=
再简单来说,层级不⼀样。
Htpp是⼀个⾮持久化协议。
HTTP的⽣命周期通过Request来界定,也就是⼀个Request ⼀个Response,那么在HTTP1.0中,这次HTTP请求就结束了。
在HTTP1.1中进⾏了改进,使得有⼀个keep-alive,也就是说,在⼀个HTTP连接中,可以发送多个Request,接收多个Response。
但是请记住 Request = Response , 在HTTP中永远是这样,也就是说⼀个request只能有⼀个response。⽽且这个response也是被动的,不能主动发起。
那么问题来了,我要想服务器这边发⽣了什么变化,怎么通知客户端呢?http轮询问是可以做到的。但是,频繁的建⽴连接删除连接⾮常的消耗资源,⽽且并不能达到实时通知,因为你轮询总会有事件间隔。
websocket就是解决这种问题的⼀种服务器推送技术。
websocket优点
websocket是⼀个全双通的协议,会在服务器与客户端建⽴⼀个长连接,相互之间可以通讯。
WebSocket是HTML5下⼀种新的协议。它实现了浏览器与服务器全双⼯通信,能更好的节省服务器资源和带宽并达到实时通讯的⽬的。它与HTTP⼀样通过已建⽴的TCP连接来传输数据,但是它和HTTP最⼤不同是:
WebSocket是⼀种双向通信协议。在建⽴连接后,WebSocket服务器端和客户端都能主动向对⽅发送或接收数据,就像Socket⼀样;
WebSocket需要像TCP⼀样,先建⽴连接,连接成功后才能相互通信。
它的特点:
(1)建⽴在 TCP 协议之上,服务器端的实现⽐较容易。
(2)与 HTTP 协议有着良好的兼容性。默认端⼝也是80和443,并且握⼿阶段采⽤ HTTP 协议,因此握⼿时不容易屏蔽,能通过各种HTTP 代理服务器。
(3)数据格式⽐较轻量,性能开销⼩,通信⾼效。
(4)可以发送⽂本,也可以发送⼆进制数据。
(5)没有同源限制,客户端可以与任意服务器通信。
(6)协议标识符是ws(如果加密,则为wss),服务器⽹址就是 URL。
例如:
ws://example:80/some/path
传统HTTP客户端与服务器请求响应模式如下图所⽰:
WebSocket模式客户端与服务器请求响应模式如下图:
上图对⽐可以看出,相对于传统HTTP每次请求-应答都需要客户端与服务端建⽴连接的模式,WebSo
cket是类似Socket的TCP长连接通讯模式。⼀旦WebSocket连接建⽴后,后续数据都以帧序列的形式传输。在客户端断开WebSocket连接或Server端中断连接前,不需要客户端和服务端重新发起连接请求。在海量并发及客户端与服务器交互负载流量⼤的情况下,极⼤的节省了⽹络带宽资源的消耗,有明显的性能优势,且客户端发送和接受消息是在同⼀个持久连接上发起,实时性优势明显。
websocket协议建⽴过程
Websocket握⼿
GET /chat HTTP/1.1
Host: ample
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: example
其中
Upgrade: websocket
Connection: Upgrade
这个就是Websocket的核⼼了,告诉Apache、Nginx等服务器:注意啦,窝发起的是Websocket协议,快点帮我到对应的助理处理~不是那个⽼⼟的HTTP。
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
⾸先,Sec-WebSocket-Key 是⼀个Base64 encode的值,这个是浏览器随机⽣成的,告诉服务器:泥煤,不要忽悠窝,我要验证尼是不是真的是Websocket助理。
然后,Sec_WebSocket-Protocol 是⼀个⽤户定义的字符串,⽤来区分同URL下,不同的服务所需要的协议。简单理解:今晚我要服务A,别搞错啦~
最后,Sec-WebSocket-Version 是告诉服务器所使⽤的Websocket Draft(协议版本),在最初的时候,Websocket协议还在 Draft 阶段,各种奇奇怪怪的协议都有,⽽且还有很多期奇奇怪怪不同的东西,什么Firefox和Chrome⽤的不是⼀个版本之类的,当初Websocket 协议太多可是⼀个⼤难题。。不过现在还好,已经定下来啦~⼤家都使⽤的⼀个东西~ 脱⽔:服务员,我要的是13岁的噢→_→
然后服务器会返回下列东西,表⽰已经接受到请求, 成功建⽴Websocket啦!
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat
这⾥开始就是HTTP最后负责的区域了,告诉客户,我已经成功切换协议啦~
Upgrade: websocket
Connection: Upgrade
依然是固定的,告诉客户端即将升级的是Websocket协议,⽽不是mozillasocket,lurnarsocket或者shitsocket。
然后,Sec-WebSocket-Accept 这个则是经过服务器确认,并且加密过后的 Sec-WebSocket-Key。服务器:好啦好啦,知道啦,给你看我的ID CARD来证明⾏了吧。。
后⾯的,Sec-WebSocket-Protocol 则是表⽰最终使⽤的协议。
⾄此,HTTP已经完成它所有⼯作了,接下来就是完全按照Websocket协议进⾏了。
代码部分
后端
这是后台接受请求的代码,当然这⾥我写成了⼀个⼦包的形式。需要的时候,在你的项⽬⾥⾯引⼊⼀下即可使⽤。
package com.haogenmin.websocket.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.haogenmin.websocket.manager.IWebSocketManager;
import com.haogenmin.websocket.manager.impl.WebSocketManager;
import com.haogenmin.websocket.service.IWebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
/**
* @author :HaoGenmin
* @Title :WebSocketServer
* @date :Created in 2020/6/13 16:41
* @description :websocket
*/
public abstract class WebSocketServer implements IWebSocketServer {
private Logger logger = Logger(WebSocketServer.class);
private IWebSocketManager webSocketManager;
//与某个客户端的连接会话,需要通过它来给客户端发送数据
private Session session;
//⽤户标记
private String userId;
@OnOpen
public void open(@PathParam("userId") String userId, Session session) {
// 添加初始化操作
logger.info("---初始化----userId:" + userId);
this.session = session;
//获取当前登录⽤户的id
this.userId = userId;
this.webSocketManager = Instance();
webSocketManager.addWebSocketServer(userId, this);    //加⼊map中
}
@OnMessage
public abstract void getMessage(String message, Session session);
@OnClose
public void close() {
// 添加关闭会话时的操作
logger.info("⽤户" + userId + "的连接关闭!当前在线⼈数为" + OnlineCount());    }
@OnError
public void error(Throwable t) {
logger.info("websocket发⽣错误");
t.printStackTrace();
t.printStackTrace();
}
public synchronized void sendMessageAsync(String message) {
AsyncRemote().sendText(message);//⾮阻塞式的
}
public synchronized void sendMessage(String message) {
try {
BasicRemote().sendText(message);
} catch (IOException e) {
e.printStackTrace();
}
}
public synchronized void sendMessage(String message, boolean isLast) {
try {
BasicRemote().sendText(message, isLast);
} catch (IOException e) {
e.printStackTrace();
}
}
public Session getSession() {
return session;
}
public String getUserId() {
return userId;
}
}
这⾥是写了⼀个管理类,可以向所有的连接或者个别连接发送请求。package com.haogenmin.websocket.manager.impl;
import com.haogenmin.websocket.manager.IWebSocketManager;
import com.haogenmin.websocket.service.IWebSocketServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Map;
import urrent.ConcurrentHashMap;
/**
* @author :HaoGenmin
java源代码加密* @Title :WebSocketManager
* @date :Created in 2020/6/13 16:57
* @description:
*/
public class WebSocketManager implements IWebSocketManager {
private static final WebSocketManager instance = new WebSocketManager();
private WebSocketManager() {
}
public static WebSocketManager getInstance() {
return instance;

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。