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協議,可以對著協議看每一個位元組的含義。

大白鯊如何抓本機的包,參考這裡 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 |