javascript
Netty与Spring WebSocket
剛開始的時(shí)候,我嘗試著用netty實(shí)現(xiàn)了websocket服務(wù)端的搭建。在netty里面,并沒有websocket session這樣的概念,與其類似的是channel,每一個(gè)客戶端連接都代表一個(gè)channel。前端的ws請求通過netty監(jiān)聽的端口,走websocket協(xié)議進(jìn)行ws握手連接之后,通過一些列的handler(責(zé)鏈模式)進(jìn)行消息處理。與websocket session類似地,服務(wù)端在連接建立后有一個(gè)channel,我們可以通過channel進(jìn)行與客戶端的通信
/*** TODO 根據(jù)服務(wù)器傳進(jìn)來的id,分配到不同的group*/private static final ChannelGroup GROUP = new DefaultChannelGroup(ImmediateEventExecutor.INSTANCE);@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception {//retain增加引用計(jì)數(shù),防止接下來的調(diào)用引用失效System.out.println("服務(wù)器接收到來自 " + ctx.channel().id() + " 的消息: " + msg.text());//將消息發(fā)送給group里面的所有channel,也就是發(fā)送消息給客戶端GROUP.writeAndFlush(msg.retain());}那么,服務(wù)端用netty還是用spring websocket?以下我將從幾個(gè)方面列舉這兩種實(shí)現(xiàn)方式的優(yōu)缺點(diǎn)
使用netty實(shí)現(xiàn)websocket
玩過netty的人都知道netty是的線程模型是nio模型,并發(fā)量非常高,spring5之前的網(wǎng)絡(luò)線程模型是servlet實(shí)現(xiàn)的,而servlet不是nio模型,所以在spring5之后,spring的底層網(wǎng)絡(luò)實(shí)現(xiàn)采用了netty。如果我們單獨(dú)使用netty來開發(fā)websocket服務(wù)端,速度快是絕對的,但是可能會遇到下列問題:
1.與系統(tǒng)的其他應(yīng)用集成不方便,在rpc調(diào)用的時(shí)候,無法享受springcloud里feign服務(wù)調(diào)用的便利性
2.業(yè)務(wù)邏輯可能要重復(fù)實(shí)現(xiàn)
3.使用netty可能需要重復(fù)造輪子
4.怎么連接上服務(wù)注冊中心,也是一件麻煩的事情
5.restful服務(wù)與ws服務(wù)需要分開實(shí)現(xiàn),如果在netty上實(shí)現(xiàn)restful服務(wù),有多麻煩可想而知,用spring一站式restful開發(fā)相信很多人都習(xí)慣了。
使用spring websocket實(shí)現(xiàn)ws服務(wù)
spring websocket已經(jīng)被springboot很好地集成了,所以在springboot上開發(fā)ws服務(wù)非常方便,做法非常簡單
第一步:添加依賴
第二步:添加配置類
@Configuration public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(myHandler(), "/").setAllowedOrigins("*"); }@Beanpublic WebSocketHandler myHandler() {return new MessageHandler();} }第三步:實(shí)現(xiàn)消息監(jiān)聽類
@Component @SuppressWarnings("unchecked") public class MessageHandler extends TextWebSocketHandler {private List<WebSocketSession> clients = new ArrayList<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) {clients.add(session);System.out.println("uri :" + session.getUri());System.out.println("連接建立: " + session.getId());System.out.println("current seesion: " + clients.size());}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {clients.remove(session);System.out.println("斷開連接: " + session.getId());}@Overrideprotected void handleTextMessage(WebSocketSession session, TextMessage message) {String payload = message.getPayload();Map<String, String> map = JSONObject.parseObject(payload, HashMap.class);System.out.println("接受到的數(shù)據(jù)" + map);clients.forEach(s -> {try {System.out.println("發(fā)送消息給: " + session.getId());s.sendMessage(new TextMessage("服務(wù)器返回收到的信息," + payload));} catch (Exception e) {e.printStackTrace();}});} }從這個(gè)demo中,使用spring websocket實(shí)現(xiàn)ws服務(wù)的便利性大家可想而知了。為了能更好地向spring cloud大家族看齊,我最終采用了spring websocket實(shí)現(xiàn)ws服務(wù)。
因此我的應(yīng)用服務(wù)架構(gòu)是這樣子的:一個(gè)應(yīng)用既負(fù)責(zé)restful服務(wù),也負(fù)責(zé)ws服務(wù)。沒有將ws服務(wù)模塊拆分是因?yàn)椴鸱殖鋈ヒ褂胒eign來進(jìn)行服務(wù)調(diào)用。第一本人比較懶惰,第二拆分與不拆分相差在多了一層服務(wù)間的io調(diào)用,所以就沒有這么做了。
總結(jié)
以上是生活随笔為你收集整理的Netty与Spring WebSocket的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于WebSocket分布式实现的一种方
- 下一篇: linux的TCP连接数量最大不能超过6