這篇隨筆暫時不講原理,首先搭建起一個簡單的能夠實現通訊的Demo。以後的一系列隨筆會進行一些原理上的分享。html
不過在這以前你們最好了解一下Netty的線程模型和NIO編程模型,會對它的總體邏輯有所瞭解。前端
更新一篇關於NIO的博客:手動搭建I/O網絡通訊框架3:NIO編程模型,升級改造聊天室web
首先建立好項目後在pom.xml引入Netty依賴編程
<dependency> <groupId>io.netty</groupId> <artifactId>netty-all</artifactId> </dependency>
用Netty搭建一個WebSocket服務器總體上須要三樣東西,無論是否是用的SpringBoot框架,這三樣東西是必不可少的。json
1.啓動服務器的類(NettyServer),會進行一些初步的配置工做。後端
2.助手類(Handler),有本身定義的助手類,也有Netty提供的一些基本的助手類,好比對Http、WebSocket支持的助手類。api
3.初始化器(Initializer),咱們下面使用的是主從線程模型,從線程組裏會分配出不一樣channel去處理不一樣客戶端的請求,而每一個channel裏就會有各類助手類去實現一些功能。初始化器的做用就是對各類助手類進行綁定。
瀏覽器
服務器啓動類:服務器
public class NettyServer { private static int port; public NettyServer(int port) { this.port = port; } public static void start() throws InterruptedException {//在main方法裏調用這個方法,並用構造函數設置端口號 //建立主線程組,接收請求 EventLoopGroup bossGroup = new NioEventLoopGroup(); //建立從線程組,處理主線程組分配下來的io操做 EventLoopGroup workerGroup = new NioEventLoopGroup(); //建立netty服務器 try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.group(bossGroup, workerGroup)//設置主從線程組 .channel(NioServerSocketChannel.class)//設置通道 .childHandler(new NettyServerInitializer());//子處理器,用於處理workerGroup中的操做 //啓動server ChannelFuture channelFuture = serverBootstrap.bind(port).sync(); //監聽關閉channel channelFuture.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully();//關閉主線程 workerGroup.shutdownGracefully();//關閉從線程 } } }
初始化器:websocket
public class NettyServerInitializer extends ChannelInitializer<SocketChannel> { @Override protected void initChannel(SocketChannel socketChannel) throws Exception { ChannelPipeline pipeline= socketChannel.pipeline(); //如下三個是Http的支持 //http解碼器 pipeline.addLast(new HttpServerCodec()); //支持寫大數據流 pipeline.addLast(new ChunkedWriteHandler()); //http聚合器 pipeline.addLast(new HttpObjectAggregator(1024*62)); //websocket支持,設置路由 pipeline.addLast(new WebSocketServerProtocolHandler("/ws")); //添加自定義的助手類 pipeline.addLast(new NettyHandler()); } }
自定義助手類:
這個類就是業務的核心,客戶端的請求會在這裏處理。好比客戶端鏈接、客戶端發送消息、給客戶端發送消息等等。
自定義助手類須要重寫的方法能夠根據本身的需求重寫,這裏就不把每一個方法都重寫一遍了,完整的你們能夠去找找文檔看看。
若是須要在助手類中用到@Autowire註解,能夠參考這個博客,網上有不少說明,這裏就再也不重複了https://blog.csdn.net/weixin_30828379/article/details/95009595
public class NettyHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {//TextWebSocketFrame是netty用於處理websocket發來的文本對象 //全部正在鏈接的channel都會存在這裏面,因此也能夠間接表明在線的客戶端 public static ChannelGroup channelGroup = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); //在線人數 public static int online; //接收到客戶都發送的消息 @Override public void channelRead0(ChannelHandlerContext ctx, TextWebSocketFrame msg) throws Exception { SendAllMessages(ctx,send_message);//send_message是個人自定義類型,先後端分離每每須要統一數據格式,能夠先把對象轉成json字符串再發送給客戶端 } //客戶端創建鏈接 @Override public void handlerAdded(ChannelHandlerContext ctx) throws Exception { channelGroup.add(ctx.channel()); online=channelGroup.size(); System.out.println(ctx.channel().remoteAddress()+"上線了!"); } //關閉鏈接 @Override public void handlerRemoved(ChannelHandlerContext ctx) throws Exception { channelGroup.remove(ctx.channel()); online=channelGroup.size(); System.out.println(ctx.channel().remoteAddress()+"斷開鏈接"); } //出現異常 @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { cause.printStackTrace(); } //給某我的發送消息 private void SendMessage(ChannelHandlerContext ctx, Send_Message msg) { ctx.channel().writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg))); } //給每一個人發送消息,除發消息人外 private void SendAllMessages(ChannelHandlerContext ctx,Send_Message msg) { for(Channel channel:channelGroup){ if(!channel.id().asLongText().equals(ctx.channel().id().asLongText())){ channel.writeAndFlush(new TextWebSocketFrame(JSON.toJSONString(msg))); } } } }
前端建立WebSocket對象進行訪問
經過socket就能夠用一些api進行發送消息,接收消息的操做。而後把接收的數據按各自的需求展現出來就好了,前端部分就再也不贅述了。
下面8088端口記得要在main方法裏面設置。
if (window.WebSocket) { var host = window.location.hostname; var url = "ws://" + host + ":8088/ws"; var socket = new WebSocket(url); }else{ alert("你的瀏覽器不支持WebSocket。請不要使用低版本的IE瀏覽器。"); }