Netty4 websocke实现聊天功能
生活随笔
收集整理的這篇文章主要介紹了
Netty4 websocke实现聊天功能
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
目錄
- 應用結構
- 直接粘代碼
- 運行結果
應用結構
直接粘代碼
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.moreday</groupId><artifactId>chatnetty</artifactId><packaging>war</packaging><version>0.0.1-SNAPSHOT</version><name>chatnetty Maven Webapp</name><url>http://maven.apache.org</url><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.1.RELEASE</version><relativePath /> <!-- lookup parent from repository --></parent><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding><java.version>1.8</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.2</version> </dependency> --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency><dependency><groupId>net.sourceforge.nekohtml</groupId><artifactId>nekohtml</artifactId></dependency><!-- https://mvnrepository.com/artifact/io.netty/netty-all --><dependency><groupId>io.netty</groupId><artifactId>netty-all</artifactId></dependency><!-- https://mvnrepository.com/artifact/org.msgpack/msgpack --><dependency><groupId>org.msgpack</groupId><artifactId>msgpack</artifactId><version>0.6.12</version></dependency><!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java --><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java</artifactId><version>3.11.4</version></dependency><!-- https://mvnrepository.com/artifact/com.google.protobuf/protobuf-java-util --><dependency><groupId>com.google.protobuf</groupId><artifactId>protobuf-java-util</artifactId><version>3.11.4</version></dependency><!-- https://mvnrepository.com/artifact/junit/junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><scope>test</scope></dependency></dependencies><build><finalName>chatnetty</finalName><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build> </project>application.properties
server.port=8089#spring.datasource.jdbc-url=jdbc:mysql://localhost:3306/babaytun?useUnicode=true&characterEncoding=utf-8&useSSL=false #spring.datasource.username=root #spring.datasource.password=root #spring.datasource.driver-class-name=com.mysql.jdbc.Driver #first.datasource.type=com.alibaba.druid.pool.DruidDataSource ############################################################ spring.thymeleaf.prefix=/WEB-INF/html spring.thymeleaf.suffix=.html spring.thymeleaf.mode=LEGACYHTML5 spring.thymeleaf.encoding=UTF-8 spring.thymeleaf.content-type=text/html spring.thymeleaf.cache=falseWebsocketChatClient.html
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>WebSocket Chat</title> </head> <body><script type="text/javascript">var socket;if (!window.WebSocket) {window.WebSocket = window.MozWebSocket;}if (window.WebSocket) {socket = new WebSocket("ws://localhost:8080/ws");socket.onmessage = function(event) {var ta = document.getElementById('responseText');ta.value = ta.value + '\n' + event.data};socket.onopen = function(event) {var ta = document.getElementById('responseText');ta.value = "連接開啟!";};socket.onclose = function(event) {var ta = document.getElementById('responseText');ta.value = ta.value + "連接被關閉";};} else {alert("你的瀏覽器不支持 WebSocket!");}function send(message) {if (!window.WebSocket) {return;}if (socket.readyState == WebSocket.OPEN) {socket.send(message);} else {alert("連接沒有開啟.");}}</script><form onsubmit="return false;"><h3>WebSocket 聊天室:</h3><textarea id="responseText" style="width: 500px; height: 300px;"></textarea><br> <input type="text" name="message" style="width: 300px" value="尋找手藝人"><input type="button" value="發送消息" onclick="send(this.form.message.value)"><input type="button" onclick="javascript:document.getElementById('responseText').value=''" value="清空聊天記錄"></form><br> <br> <a href="https://blog.csdn.net/u012637358/" >更多例子請訪問 https://blog.csdn.net/u012637358</a> </body> </html>啟動入口類
package com.moreday.netty_websocket;import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.ResponseBody; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.ModelAndView;/*** @ClassName Example* @Description TODO(這里用一句話描述這個類的作用)* @author 尋找手藝人* @Date 2020年4月19日 下午8:27:00* @version 1.0.0*/ @Controller @EnableAutoConfiguration public class Example {@RequestMapping(value ="/index", method = RequestMethod.GET)public ModelAndView index() {ModelAndView mv = new ModelAndView();mv.setViewName("/WebsocketChatClient");return mv;}@RequestMapping(value ="/home", method = RequestMethod.GET)@ResponseBodypublic String home(){return "index.html";}public static void main(String[] args){SpringApplication.run(Example.class, args);}}WebsocketChatServer.java
package com.moreday.netty_websocket;import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.nio.NioServerSocketChannel;/*** @ClassName WebsocketChatServer* @Description TODO(這里用一句話描述這個類的作用)* @author 尋找手藝人* @Date 2020年4月17日 下午6:34:33* @version 1.0.0*/ public class WebsocketChatServer {private int port;public WebsocketChatServer(int port) {this.port = port;}public void run() throws Exception {EventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)EventLoopGroup workerGroup = new NioEventLoopGroup();try {ServerBootstrap b = new ServerBootstrap(); // (2)b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // (3).childHandler(new WebsocketChatServerInitializer()) //(4).option(ChannelOption.SO_BACKLOG, 128) // (5).childOption(ChannelOption.SO_KEEPALIVE, true); // (6)System.out.println("WebsocketChatServer 啟動了");// 綁定端口,開始接收進來的連接ChannelFuture f = b.bind(port).sync(); // (7)// 等待服務器 socket 關閉 。// 在這個例子中,這不會發生,但你可以優雅地關閉你的服務器。f.channel().closeFuture().sync();} finally {workerGroup.shutdownGracefully();bossGroup.shutdownGracefully();System.out.println("WebsocketChatServer 關閉了");}}public static void main(String[] args) throws Exception {int port;if (args.length > 0) {port = Integer.parseInt(args[0]);} else {port = 8080;}new WebsocketChatServer(port).run();} }TextWebSocketFrameHandler.java
package com.moreday.netty_websocket;import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelPipeline; import io.netty.channel.socket.SocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpServerCodec; import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler; import io.netty.handler.stream.ChunkedWriteHandler;/*** @ClassName WebsocketChatServerInitializer* @Description TODO(這里用一句話描述這個類的作用)* @author 尋找手藝人* @Date 2020年4月17日 下午6:33:18* @version 1.0.0*/ public class WebsocketChatServerInitializer extends ChannelInitializer<SocketChannel> {@Overridepublic void initChannel(SocketChannel ch) throws Exception {//2ChannelPipeline pipeline = ch.pipeline();pipeline.addLast(new HttpServerCodec());pipeline.addLast(new HttpObjectAggregator(64*1024));pipeline.addLast(new ChunkedWriteHandler());pipeline.addLast(new HttpRequestHandler("/ws"));pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));pipeline.addLast(new TextWebSocketFrameHandler());} } package com.moreday.netty_websocket;import java.io.File; import java.io.RandomAccessFile; import java.net.URL; import java.util.Random;import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.DefaultFileRegion; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaderNames; import io.netty.handler.codec.http.HttpHeaderValues; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpUtil; import io.netty.handler.codec.http.HttpVersion; import io.netty.handler.codec.http.LastHttpContent; import io.netty.handler.ssl.SslHandler; import io.netty.handler.stream.ChunkedNioFile;/*** @ClassName HttpRequestHandler* @Description TODO(這里用一句話描述這個類的作用)* @author 尋找手藝人* @Date 2020年4月16日 下午11:18:18* @version 1.0.0*/ public class HttpRequestHandler extends SimpleChannelInboundHandler<FullHttpRequest>{private final String wsUri;private static final File INDEX;static {URL location = HttpRequestHandler.class.getProtectionDomain().getCodeSource().getLocation();try {String path = location.toURI()+"WebsocketChatClient.html";path = !path.contains("file:")?path:path.substring(5);INDEX = new File(path);} catch (Exception e) {// TODO: handle exceptionthrow new IllegalStateException("unable to locate WebsocketChatClient.html");}}/*** @Description TODO(這里用一句話描述這個方法的作用)*/public HttpRequestHandler(String wsUri) {// TODO Auto-generated constructor stubthis.wsUri = wsUri;}/* (非 Javadoc)* Description:* @see io.netty.channel.SimpleChannelInboundHandler#channelRead0(io.netty.channel.ChannelHandlerContext, java.lang.Object)*/@Overrideprotected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest msg) throws Exception {// TODO Auto-generated method stubif(wsUri.equalsIgnoreCase(msg.uri())) {ctx.fireChannelRead(msg.retain());}else {if(HttpUtil.is100ContinueExpected(msg)) {send100Continue(ctx);}RandomAccessFile file = new RandomAccessFile(INDEX, "r");HttpResponse response = new DefaultFullHttpResponse(msg.protocolVersion(), HttpResponseStatus.OK);response.headers().set(HttpHeaderNames.CONTENT_TYPE,"text/html;charset=UTF-8");boolean keepAlive = HttpUtil.isKeepAlive(msg);if(keepAlive) {response.headers().set(HttpHeaderNames.CONTENT_LENGTH,file.length());response.headers().set(HttpHeaderNames.CONNECTION,HttpHeaderValues.KEEP_ALIVE);}ctx.write(response);if(ctx.pipeline().get(SslHandler.class)==null) {ctx.write(new DefaultFileRegion(file.getChannel(), 0,file.length()));}else {ctx.write(new ChunkedNioFile(file.getChannel()));}ChannelFuture f = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);if(!keepAlive) {f.addListener(ChannelFutureListener.CLOSE);}file.close();}}/*** @Description (TODO這里用一句話描述這個方法的作用)* @param ctx*/private void send100Continue(ChannelHandlerContext ctx) {// TODO Auto-generated method stubFullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE);ctx.writeAndFlush(response);}} package com.moreday.netty_websocket;import io.netty.channel.Channel; import io.netty.channel.ChannelHandler; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.handler.codec.http.websocketx.TextWebSocketFrame; import io.netty.util.concurrent.GlobalEventExecutor;/*** @ClassName TextWebSocketFrameHandler* @Description TODO(這里用一句話描述這個類的作用)* @author 尋找手藝人* @Date 2020年4月17日 下午6:34:15* @version 1.0.0*/ public class TextWebSocketFrameHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {private ChannelGroup channels = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);@Overrideprotected void channelRead0(ChannelHandlerContext ctx,TextWebSocketFrame msg) throws Exception { // (1)Channel incoming = ctx.channel();for (Channel channel : channels) {if (channel != incoming){channel.writeAndFlush(new TextWebSocketFrame("[" + incoming.remoteAddress() + "]" + msg.text()));} else {channel.writeAndFlush(new TextWebSocketFrame("[you]" + msg.text() ));}}}/* (非 Javadoc)* Description:* @see io.netty.channel.ChannelHandler#handlerAdded(io.netty.channel.ChannelHandlerContext)*/public void handlerAdded(ChannelHandlerContext ctx) throws Exception {// TODO Auto-generated method stubChannel incoming = ctx.channel();for (Channel channel : channels) {channel.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 加入"));}channels.add(ctx.channel());System.out.println("Client:"+incoming.remoteAddress() +"加入");}/* (非 Javadoc)* Description:* @see io.netty.channel.ChannelHandler#handlerRemoved(io.netty.channel.ChannelHandlerContext)*/public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {// TODO Auto-generated method stubChannel incoming = ctx.channel();for (Channel channel : channels) {channel.writeAndFlush(new TextWebSocketFrame("[SERVER] - " + incoming.remoteAddress() + " 離開"));}System.out.println("Client:"+incoming.remoteAddress() +"離開");channels.remove(ctx.channel());}@Overridepublic void channelActive(ChannelHandlerContext ctx) throws Exception { // (5)Channel incoming = ctx.channel();System.out.println("Client:"+incoming.remoteAddress()+"在線");}@Overridepublic void channelInactive(ChannelHandlerContext ctx) throws Exception { // (6)Channel incoming = ctx.channel();System.out.println("Client:"+incoming.remoteAddress()+"掉線");}/* (非 Javadoc)* Description:* @see io.netty.channel.ChannelHandler#exceptionCaught(io.netty.channel.ChannelHandlerContext, java.lang.Throwable)*/public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {// TODO Auto-generated method stubChannel incoming = ctx.channel();System.out.println("Client:"+incoming.remoteAddress()+"異常");// 當出現異常就關閉連接cause.printStackTrace();ctx.close();}}運行結果
啟動WebsocketChatServer,啟動Example
訪問客戶端
總結
以上是生活随笔為你收集整理的Netty4 websocke实现聊天功能的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 检测出DNF服务器未响应,dnf老是卡死
- 下一篇: 线程可见性和关键字volatile