使用netty搭建一个简单的聊天室
1.導(dǎo)入maven依賴
? ? ? ?<dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId><version>4.1.25.Final</version></dependency>2.ChannelHandler
我們需要寫(xiě)一個(gè)處理消息的handler,繼承SimpleChannelInboundHandler即可,然后實(shí)現(xiàn)我們需要實(shí)現(xiàn)的幾個(gè)方法。
因?yàn)槲覀円罱ǖ氖且粋€(gè)聊天室,所以需要有一個(gè)對(duì)象ChannelGroup來(lái)將所有客戶端保存起來(lái)。每當(dāng)一個(gè)用戶連接到服務(wù)器,就將該用戶所在的通道加入到該對(duì)象中。當(dāng)任一用戶發(fā)送消息,將消息遍歷發(fā)送給所有用戶。
/*** 處理消息的handler* TextWebSocketFrame: 在netty中,是用于為websocket專(zhuān)門(mén)處理文本的對(duì)象,frame是消息的載體*/ public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> { ?/*** 用來(lái)保存所有的客戶端連接*/private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);private SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm"); ?/*** 當(dāng)Channel中有新的事件消息會(huì)自動(dòng)調(diào)用*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) {// 當(dāng)接收到數(shù)據(jù)后會(huì)自動(dòng)調(diào)用 ?// 獲取客戶端發(fā)送過(guò)來(lái)的文本消息String text = msg.text();System.out.println("接收到消息數(shù)據(jù)為:" + text); ?for (Channel client : clients) {// 將消息發(fā)送到所有的客戶端client.writeAndFlush(new TextWebSocketFrame(sdf.format(new Date()) + ":" + text));}} ?/*** 當(dāng)有新的客戶端連接服務(wù)器之后,會(huì)自動(dòng)調(diào)用這個(gè)方法*/@Overridepublic void handlerAdded(ChannelHandlerContext ctx) {// 將新的通道加入到clientsclients.add(ctx.channel());} }3.ChannelHandler
ChannelInitializer的主要目的是為程序員提供了一個(gè)簡(jiǎn)單的工具,用于在某個(gè)Channel注冊(cè)到EventLoop后,對(duì)這個(gè)Channel執(zhí)行一些初始化操作。ChannelInitializer雖然會(huì)在一開(kāi)始被注冊(cè)到Channel相關(guān)的pipeline里,但是在初始化完成之后,ChannelInitializer會(huì)將自己從pipeline中移除,不會(huì)影響后續(xù)的操作。
/*** 通道初始化器* 用來(lái)加載通道處理器(ChannelHandler)*/ public class WebSocketChannelInitializer extends ChannelInitializer<SocketChannel> { ?// 初始化通道// 在這個(gè)方法中去加載對(duì)應(yīng)的ChannelHandler@Overrideprotected void initChannel(SocketChannel ch) throws Exception {// 獲取管道,將一個(gè)一個(gè)的ChannelHandler添加到管道中ChannelPipeline pipeline = ch.pipeline(); ?// 添加一個(gè)http的編解碼器pipeline.addLast(new HttpServerCodec());// 添加一個(gè)用于支持大數(shù)據(jù)流的支持pipeline.addLast(new ChunkedWriteHandler());// 添加一個(gè)聚合器,這個(gè)聚合器主要是將HttpMessage聚合成FullHttpRequest/Responsepipeline.addLast(new HttpObjectAggregator(1024 * 64)); ?// 需要指定接收請(qǐng)求的路由// 必須使用以ws后綴結(jié)尾的url才能訪問(wèn)pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); ?// 添加自定義的Handlerpipeline.addLast(new ChatHandler());} }4.客戶端server
public class WebSocketNettyServer {public static void main(String[] args) {// 創(chuàng)建兩個(gè)線程池NioEventLoopGroup mainGrp = new NioEventLoopGroup(); // 主線程池NioEventLoopGroup subGrp = new NioEventLoopGroup(); // 從線程池 ?try {// 創(chuàng)建Netty服務(wù)器啟動(dòng)對(duì)象ServerBootstrap serverBootstrap = new ServerBootstrap(); ?// 初始化服務(wù)器啟動(dòng)對(duì)象serverBootstrap// 指定使用上面創(chuàng)建的兩個(gè)線程池.group(mainGrp, subGrp)// 指定Netty通道類(lèi)型.channel(NioServerSocketChannel.class)// 指定通道初始化器用來(lái)加載當(dāng)Channel收到事件消息后,// 如何進(jìn)行業(yè)務(wù)處理.childHandler(new WebSocketChannelInitializer()); ?// 綁定服務(wù)器端口,以同步的方式啟動(dòng)服務(wù)器ChannelFuture future = serverBootstrap.bind(9090).sync();// 等待服務(wù)器關(guān)閉future.channel().closeFuture().sync();} catch (InterruptedException e) {e.printStackTrace();} finally {// 優(yōu)雅關(guān)閉服務(wù)器mainGrp.shutdownGracefully();subGrp.shutdownGracefully();} ?} }5.html頁(yè)面
<!DOCTYPE html> <html lang="en"> <head><meta charset="UTF-8"><title>在線聊天室</title> </head> <body><input type="text" id="message"><input type="button" value="發(fā)送消息" onclick="sendMsg()"> ?接收到的消息:<p id="server_message" style="background-color: #AAAAAA"></p> ?<script> ?var websocket = null; ?// 判斷當(dāng)前瀏覽器是否支持websocketif(window.WebSocket) {websocket = new WebSocket("ws://127.0.0.1:9090/ws"); ?websocket.onopen = function() {console.log("建立連接.");}websocket.onclose = function() {console.log("斷開(kāi)連接");}websocket.onmessage = function(e) {console.log("接收到服務(wù)器消息:" + e.data);var server_message = document.getElementById("server_message");server_message.innerHTML += e.data + "<br/>";}}else {alert("當(dāng)前瀏覽器不支持web socket");} ?function sendMsg() {var message = document.getElementById("message");websocket.send(message.value);}</script> </body> </html>6.測(cè)試
打開(kāi)多個(gè)頁(yè)面,然后發(fā)送消息,不同頁(yè)面都能實(shí)時(shí)的顯示不同頁(yè)面發(fā)送的消息。
?
?
?
總結(jié)
以上是生活随笔為你收集整理的使用netty搭建一个简单的聊天室的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: MYSQL数据库设计原则
- 下一篇: 使用netty实现一个类似于微信的聊天功