springboot + websocket 例子
本文為springboot加原生websocket例子,本文沒有包含stomp協議相關內容。
GITHUB
xwjie/SpringBootStompDemo
原生websocket
原生socket需要用 @ServerEndpoint
發布服務, 使用 @OnOpen
, @OnClose
, @OnMessage
, @OnError
等監聽事件即可!
配置websocket
@Configurationnpublic class BaseWebSocketConfig {n @Beann public ServerEndpointExporter serverEndpointExporter() {n return new ServerEndpointExporter();n }n}n
發布服務
使用 @ServerEndpoint
發布服務。
每一個鏈接會新創建一個實例,所以完全可以把Session做為屬性放在類裡面。
這個bean的作用域【應該】是prototype。@ServerEndpoint
在裡面注入其他的bean沒有成功。增加了 @Scope(TARGET_CLASS)也不行。
所以暫時用靜態方法。
@ServerEndpoint(value = "/basews")n@Componentnpublic class BaseWebSocket {nn public BaseWebSocket() {n System.out.println("n-----new BaseWebSocket-----n");n }nn // FIXME 無法注入bean ?n // @Autowiredn // SessionService sessionService;nn @OnOpenn public void onOpen(Session session) {n SessionService.newSession(session);n }nn @OnClosen public void onClose(Session session) {n SessionService.closeSession(session);n }nn @OnMessagen public void onMessage(String message, Session session) {n System.out.println(session.getId() + " > OnMessage: " + message);n SessionService.sendMessage(session, "this is a message from server!");n }nn @OnErrorn public void onError(Session session, Throwable throwable) {n System.out.println(session.getId() + " > OnError: " + throwable.getMessage());nn throwable.printStackTrace();nn SessionService.closeSession(session);n }nn}n
Session管理
單獨整了個類來集中處理Session。
public class SessionService {nn private static AtomicInteger count = new AtomicInteger();nn private static Map<String, Session> sessionMap = new ConcurrentHashMap<>();nn public static void newSession(Session session) {n sessionMap.put(session.getId(), session);nn System.out.println("new session, now count=" + count.incrementAndGet());n }nn public static void closeSession(Session session) {n sessionMap.remove(session.getId());nn System.out.println("close session, now count=" + count.decrementAndGet());n }nn /**n * 發送消息到客戶端n * n * @param sessionn * @param messagen */n @SneakyThrowsn public static void sendMessage(Session session, String message) {n session.getBasicRemote().sendText(message);n // session.getAsyncRemote().sendText(message);n }nn}n
測試
打開chrome,在console裡面測試
var ws = new WebSocket("ws://127.0.0.1:8080/basews");nws.onmessage = function(msg){console.log("接受到消息", msg)};nws.send("hello");nn// 在開一個鏈接nvar ws2 = new WebSocket("ws://127.0.0.1:8080/basews");n
WebSocket 協議簡單分析
建立連接使用http協議,伺服器返回101切換協議。因為是http協議,所以可以在小提琴fiddler上監控到。
可以看到cookie也帶了,就是一個普通的http請求,只是多了一些頭。
101之後切換協議,之後就不再是http協議了(但是埠還是http的8080),fiddler上無法監控到,但chrome上可以看到對應的frame幀。
發送內容需要使用抓包工具,這裡用的是wireshark大白鯊。
可以設別為websocket協議,可以對著協議看每一個位元組的含義。
大白鯊如何抓本機的包,參考這裡 https://www.bbsmax.com/A/A2dmxVpg5e/ 。 我這裡使用的第二種,第一種方法才看到。
spring 筆記
隨機埠
使用隨機埠,就可以啟動2個SpringBoot了。使用 @LocalServerPort
注入當前的服務的埠。
@RunWith(SpringRunner.class)n@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)npublic class GreetingIntegrationTests {nn @LocalServerPortn private int port;nn}n
代碼修改後自動重啟
<!-- 更新代碼自動重啟 -->n<dependency>nt<groupId>org.springframework.boot</groupId>nt<artifactId>spring-boot-devtools</artifactId>n</dependency>n
推薦閱讀:
※tornado如何實現非同步websocket推送?
※對於 Socket 粘包的困惑?
※MQTT和Websocket的區別是什麼?
TAG:SpringBoot | WebSocket |