一、前言
WebSocket 是 HTML5 開始提供的一種在單個(gè) TCP 連接上進(jìn)行全雙工通訊的協(xié)議。
HTML5 定義的 WebSocket 協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時(shí)地進(jìn)行通訊。
HTML5 定義的 WebSocket 協(xié)議,能更好的節(jié)省服務(wù)器資源和帶寬,并且能夠更實(shí)時(shí)地進(jìn)行通訊。
瀏覽器通過(guò) JavaScript 向服務(wù)器發(fā)出建立 WebSocket 連接的請(qǐng)求,連接建立以后,客戶端和服務(wù)器端就可以通過(guò) TCP 連接直接交換數(shù)據(jù)。
二、快速搭建springboot-websocket項(xiàng)目的服務(wù)端
1 導(dǎo)入依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
2 創(chuàng)建配置類
@Configuration
public class WebSocketConfig {
@Bean
public ServerEndpointExporter serverEndpointExporter() {
return new ServerEndpointExporter();
}
}
3 創(chuàng)建WebSocketServer服務(wù)類 用來(lái)接收數(shù)據(jù)
websocket的常用注解只有這5個(gè)
@ServerEndpoint注意上下文路徑,websocket連接地址
@OnMessage只有第一次加載websocket的時(shí)候,會(huì)調(diào)用,生命周期只有一次
@OnClose只有關(guān)閉websocket鏈接的時(shí)候,會(huì)調(diào)用,生命周期只有一次
@OnMessage每次接收信息的時(shí)候,都會(huì)調(diào)用,調(diào)用比較頻繁
@OnError發(fā)生錯(cuò)誤的時(shí)候調(diào)調(diào)用
/**
* 類似RequestMapping的地址
* ws://localhost:8080/ws/000001
*/
@ServerEndpoint("/ws/{uuid}")
@Component
public class WebSocketServer {
private Session session; //客戶端會(huì)話
//存放每個(gè)客戶端的連接會(huì)話
public static ConcurrentHashMap<String,WebSocketServer> clients = new ConcurrentHashMap<>();
//開啟連接
//存入連接回話中
@OnOpen
public void onOpen(Session session, @PathParam( "uuid") String uuid){
System.out.println("當(dāng)前的uuid為:"+uuid);
this.session = session;
clients.put(uuid,this);
}
//發(fā)送消息
@OnMessage
public void OnMessage(String msg, @PathParam( "uuid") String uuid){
System.out.println("當(dāng)前的uuid為:"+uuid);
System.out.println("收到消息: "+msg);
}
//關(guān)閉連接
@OnClose
public void onClose(@PathParam( "uuid") String uuid){
System.out.println("當(dāng)前的uuid為:"+uuid);
System.out.println("關(guān)閉socket連接"+uuid);
clients.remove(uuid);
}
//發(fā)生異常的情況
@OnError
public void onError(Throwable error) {
error.printStackTrace();
}
}
4 啟動(dòng)項(xiàng)目

三、一般都是前端為客戶端,后端為服務(wù)端這種方式
前端客戶端,我不會(huì),需要的自己百度,哈哈哈
四、搭建java-websocket客戶端
該案例,只是告訴大家,可以用java搭建客戶端
4.1 依賴
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.5</version>
</dependency>
4.2 客戶端代碼
@Component
public class WebSocketConfig {
@Bean
public WebSocketClient webSocketClient() {
try {
WebSocketClient webSocketClient = new WebSocketClient(new URI("ws://localhost:8081/ws/000001"),new Draft_6455()) {
@Override
public void onOpen(ServerHandshake handshakedata) {
System.out.println("ws 連接成功");
}
@Override
public void onMessage(String message) {
System.out.println("ws 收到消息"+message);
}
@Override
public void onClose(int code, String reason, boolean remote) {
System.out.println("ws 退出");
}
@Override
public void onError(Exception ex) {
System.out.println("連接錯(cuò)誤"+ex.getMessage());
}
};
webSocketClient.connect();
return webSocketClient;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
4.3 發(fā)送消息的代碼
@SpringBootApplication
@RestController
public class SpringbootWebsocketClientApplication {
@Autowired
private WebSocketClient webSocketClient;
public static void main(String[] args) {
SpringApplication.run(SpringbootWebsocketClientApplication.class, args);
}
@RequestMapping("/get")
public String send(){
webSocketClient.send("我是ws客戶端,你好?。?!");
return "發(fā)送成功";
}
}
4.4 結(jié)果

4.5 服務(wù)端收到消息
當(dāng)前的uuid為:000001
收到消息: 我是ws客戶端,你好!??!
五、websocket傳遞頭信息,協(xié)議頭token的前后端解決方案
js websocket 傳遞token
websocket協(xié)議在握手階段借用了HTTP的協(xié)議,但是在JavaScript websocketAPI中并沒(méi)有修改請(qǐng)求頭的方法。
1.1 基于協(xié)議頭
websocket請(qǐng)求頭中可以包含Sec-WebSocket-Protocol這個(gè)屬性,該屬性是一個(gè)自定義的子協(xié)議。它從客戶端發(fā)送到服務(wù)器并返回從服務(wù)器到客戶端確認(rèn)子協(xié)議。我們可以利用這個(gè)屬性添加token。
var token='fasdfadfasdfa'
var ws = new WebSocket("ws://" + url+ "/webSocketServer",[token]);
后臺(tái)取出websocket協(xié)議頭的參數(shù)
2.1 取出token
token = ((HttpServletRequest) servletRequest).getHeader("Sec-WebSocket-Protocol");
2.2 注意大坑
如果傳遞了token參數(shù),后端響應(yīng)的時(shí)候,也必須帶上這個(gè)token響應(yīng)!否則前端接收不到數(shù)據(jù)!文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-739139.html
可以采用servlet的過(guò)濾器來(lái)做文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-739139.html
@Order(1)
@Component
@WebFilter(filterName = "WebsocketFilter", urlPatterns = "/home/*")
public class WebsocketFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
String token = ((HttpServletRequest) servletRequest).getHeader("Sec-WebSocket-Protocol");
response.setHeader("Sec-WebSocket-Protocol",token);
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
}
}
六、結(jié)尾
websocket最偉大之處在于服務(wù)器和客戶端可以在給定的時(shí)間范圍內(nèi)的任意時(shí)刻,相互推送信息。 瀏覽器和服務(wù)器只需要要做一個(gè)握手的動(dòng)作,在建立連接之后,服務(wù)器可以主動(dòng)傳送數(shù)據(jù)給客戶端,客戶端也可以隨時(shí)向服務(wù)器發(fā)送數(shù)據(jù)。
第一、WebSocket是HTML5中的協(xié)議,支持持久連接;而Http協(xié)議不支持持久連接。
第二、首先,Websocket是一個(gè)持久化的協(xié)議,相對(duì)于HTTP這種非持久的協(xié)議來(lái)說(shuō)
HTTP的生命周期通過(guò) Request 來(lái)界定,也就是一個(gè) Request 一個(gè) Response ,那么在 HTTP1.0 中,這次HTTP請(qǐng)求就結(jié)束了。
在HTTP1.1中進(jìn)行了改進(jìn),使得有一個(gè)keep-alive,也就是說(shuō),在一個(gè)HTTP連接中,可以發(fā)送多個(gè)Request,接收多個(gè)Response。但是請(qǐng)記住 Request = Response , 在HTTP中永遠(yuǎn)是這樣,也就是說(shuō)一個(gè)request只能有一個(gè)response。而且這個(gè)response也是被動(dòng)的,不能主動(dòng)發(fā)起。
第三、傳統(tǒng)的http請(qǐng)求,其并發(fā)能力都是依賴同時(shí)發(fā)起多個(gè)TCP連接訪問(wèn)服務(wù)器實(shí)現(xiàn)的(因此并發(fā)數(shù)受限于瀏覽器允許的并發(fā)連接數(shù)),而websocket則允許我們?cè)谝粭lws連接上同時(shí)并發(fā)多個(gè)請(qǐng)求,即在A請(qǐng)求發(fā)出后A響應(yīng)還未到達(dá),就可以繼續(xù)發(fā)出B請(qǐng)求。由于TCP的慢啟動(dòng)特性(新連接速度上來(lái)是需要時(shí)間的),以及連接本身的握手損耗,都使得websocket協(xié)議的這一特性有很大的效率提升。
第四、http協(xié)議的頭部太大,且每個(gè)請(qǐng)求攜帶的幾百上千字節(jié)的頭部大部分是重復(fù)的,很多時(shí)候可能響應(yīng)都遠(yuǎn)沒(méi)有請(qǐng)求中的header空間大。如此多無(wú)效的內(nèi)容傳遞是因?yàn)闊o(wú)法利用上一條請(qǐng)求內(nèi)容,websocket則因?yàn)閺?fù)用長(zhǎng)連接而沒(méi)有這一問(wèn)題。
第五、當(dāng)需要實(shí)現(xiàn)客戶端刷新消息時(shí),傳統(tǒng)方案往往通過(guò)定時(shí)ajax請(qǐng)求實(shí)現(xiàn),實(shí)際上對(duì)多數(shù)用戶多數(shù)時(shí)間下這些請(qǐng)求都是無(wú)意義了,并且非常占用資源,websocket資源占用就小很多
到了這里,關(guān)于快速搭建springboot websocket客戶端的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!