Netty服务端

1.引入依赖

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.9.RELEASE</version> <!-- 我这里用的1.5.9 -->
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.blaze</groupId>
<artifactId>netty-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>netty-demo</name>
<description>Demo project for Spring Boot</description> <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-thymeleaf</artifactId>
</dependency> <dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
</dependency> <!--fastjson-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.50</version>
</dependency> <!--netty依赖-->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.43.Final</version>
</dependency> </dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<mainClass>com.blaze.nettydemo.server.WebSocketServer</mainClass>
</configuration>
</plugin>
</plugins>
<finalName>netty-server</finalName>
</build> </project>

2.服务端

WebSocketServer

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.SelfSignedCertificate; /**
* create by zy 2019/11/28 14:50
* TODO
*/
public final class WebSocketServer { //static final boolean SSL = System.getProperty("ssl") != null;
//static final int PORT = Integer.parseInt(System.getProperty("port", SSL ? "8443" : "8888"));
static final boolean SSL = false;
static final int PORT = 8888; public static void main(String[] args) throws Exception {
// Configure SSL. 配置 SSL
final SslContext sslCtx;
if (SSL) {
SelfSignedCertificate ssc = new SelfSignedCertificate();
sslCtx = SslContextBuilder.forServer(ssc.certificate(), ssc.privateKey()).build();
} else {
sslCtx = null;
}
/**
* interface EventLoopGroup extends EventExecutorGroup extends ScheduledExecutorService extends ExecutorService
* 配置服务端的 NIO 线程池,用于网络事件处理,实质上他们就是 Reactor 线程组
* bossGroup 用于服务端接受客户端连接,workerGroup 用于进行 SocketChannel 网络读写
*/
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
// ServerBootstrap 是 Netty 用于启动 NIO 服务端的辅助启动类,用于降低开发难度
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.handler(new LoggingHandler(LogLevel.INFO))
.childHandler(new WebSocketServerInitializer(sslCtx)); //服务器启动辅助类配置完成后,调用 bind 方法绑定监听端口,调用 sync 方法同步等待绑定操作完成,服务开启
Channel ch = b.bind(PORT).sync().channel();
System.out.println("服务已开启,等待客户端连接......"); //下面会进行阻塞,等待服务器连接关闭之后 main 方法退出,程序结束
ch.closeFuture().sync();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
//退出 释放资源
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
}
}

WebSocketServerInitializer

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.codec.http.websocketx.extensions.compression.WebSocketServerCompressionHandler;
import io.netty.handler.ssl.SslContext; /**
* create by zy 2019/11/28 14:53
* TODO
*/
public class WebSocketServerInitializer extends ChannelInitializer<SocketChannel> { private static final String WEBSOCKET_PATH = "/"; private final SslContext sslCtx; public WebSocketServerInitializer(SslContext sslCtx) {
this.sslCtx = sslCtx;
} @Override
public void initChannel(SocketChannel ch) {
ChannelPipeline pipeline = ch.pipeline();
if (sslCtx != null) {
pipeline.addLast(sslCtx.newHandler(ch.alloc())); // 设置 https 相关
}
pipeline.addLast(new HttpServerCodec()); // http 编码
pipeline.addLast(new HttpObjectAggregator(65536)); // http 消息聚合器
pipeline.addLast(new WebSocketServerCompressionHandler()); // 压缩 可以不设置
pipeline.addLast(new WebSocketServerProtocolHandler(WEBSOCKET_PATH, null, true)); // 协议
pipeline.addLast(new WebSocketFrameHandler()); // 处理WebSocketFrame
}
}

WebSocketFrameHandler

import com.alibaba.fastjson.JSON;
import com.rising.netty.model.RequestModel;
import com.rising.netty.model.ResultModel;
import com.rising.netty.util.MQUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.BinaryWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame; /**
* create by zy 2019/11/28 14:57
* TODO
*/
public class WebSocketFrameHandler extends SimpleChannelInboundHandler<WebSocketFrame> { @Override
protected void channelRead0(ChannelHandlerContext ctx, WebSocketFrame frame) throws Exception {
if (frame instanceof TextWebSocketFrame) {
String request = ((TextWebSocketFrame) frame).text();
System.out.println("接收消息:" + request); String msg = "接收成功";
//返回信息
ctx.channel().writeAndFlush(new TextWebSocketFrame(msg));
} else if (frame instanceof BinaryWebSocketFrame) {
//二进制
ByteBuf content = frame.content();
byte[] reg = new byte[content.readableBytes()];
content.readBytes(reg);
String request = new String(reg, "UTF-8");
System.out.println("接收消息:" + request); String msg = "接收成功";
//返回信息
ByteBuf respByteBuf = Unpooled.copiedBuffer(msg.getBytes());
ctx.channel().writeAndFlush(new BinaryWebSocketFrame(respByteBuf));
} else {
String message = "unsupported frame type: " + frame.getClass().getName();
throw new UnsupportedOperationException(message);
}
}
}

3.客户端

WebSocketClient

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.http.DefaultHttpHeaders;
import io.netty.handler.codec.http.HttpClientCodec;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.handler.codec.http.websocketx.extensions.compression.WebSocketClientCompressionHandler;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory; import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URI; /**
* create by zy 2019/11/28 14:57
* TODO
*/
public final class WebSocketClient { static final String URL = System.getProperty("url", "ws://127.0.0.1:8888/"); public static void main(String[] args) throws Exception {
URI uri = new URI(URL);
String scheme = uri.getScheme() == null ? "ws" : uri.getScheme(); final String host = uri.getHost() == null ? "127.0.0.1" : uri.getHost();
final int port;
if (uri.getPort() == -1) {
if ("ws".equalsIgnoreCase(scheme)) {
port = 80;
} else if ("wss".equalsIgnoreCase(scheme)) {
port = 443;
} else {
port = -1;
}
} else {
port = uri.getPort();
} if (!"ws".equalsIgnoreCase(scheme) && !"wss".equalsIgnoreCase(scheme)) {
System.err.println("Only WS(S) is supported.");
return;
} final boolean ssl = "wss".equalsIgnoreCase(scheme);
final SslContext sslCtx;
if (ssl) {
sslCtx = SslContextBuilder.forClient()
.trustManager(InsecureTrustManagerFactory.INSTANCE).build();
} else {
sslCtx = null;
} //配置客户端 NIO 线程组/池
EventLoopGroup group = new NioEventLoopGroup();
try {
// Connect with V13 (RFC 6455 aka HyBi-17). You can change it to V08 or V00.
// If you change it to V00, ping is not supported and remember to change
// HttpResponseDecoder to WebSocketHttpResponseDecoder in the pipeline.
final WebSocketClientHandler handler = new WebSocketClientHandler(
WebSocketClientHandshakerFactory.newHandshaker(
uri, WebSocketVersion.V13, null, true, new DefaultHttpHeaders())); /**
* Bootstrap 与 ServerBootstrap 都继承(extends)于 AbstractBootstrap
* 创建客户端辅助启动类,并对其配置,与服务器稍微不同,这里的 Channel 设置为 NioSocketChannel
* 然后为其添加 Handler,这里直接使用匿名内部类,实现 initChannel 方法
* 作用是当创建 NioSocketChannel 成功后,在进行初始化时,将它的ChannelHandler设置到ChannelPipeline中,用于处理网络I/O事件
*/
Bootstrap b = new Bootstrap();
b.group(group)
.channel(NioSocketChannel.class)
.handler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) {
ChannelPipeline p = ch.pipeline();
if (sslCtx != null) {
p.addLast(sslCtx.newHandler(ch.alloc(), host, port));
}
p.addLast(
new HttpClientCodec(),
new HttpObjectAggregator(8192),
WebSocketClientCompressionHandler.INSTANCE,
handler);
}
}); //客户端与服务端建立连接
Channel ch = b.connect(uri.getHost(), port).sync().channel();
handler.handshakeFuture().sync(); /**
* 将输入信息传输到 server 端
*/
BufferedReader console = new BufferedReader(new InputStreamReader(System.in));
while (true) {
String msg = console.readLine();
if (msg == null) {
break;
} else if ("bye".equals(msg.toLowerCase())) {
//输入bye 断开连接
ch.writeAndFlush(new CloseWebSocketFrame());
ch.closeFuture().sync();
break;
} else if ("ping".equals(msg.toLowerCase())) {
WebSocketFrame frame = new PingWebSocketFrame(Unpooled.wrappedBuffer(new byte[]{8, 1, 8, 1}));
ch.writeAndFlush(frame);
} else {
WebSocketFrame frame = new TextWebSocketFrame(msg);
ch.writeAndFlush(frame);
}
}
} finally {
group.shutdownGracefully();
}
}
}

WebSocketClientHandler

import io.netty.channel.*;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.websocketx.*;
import io.netty.util.CharsetUtil; /**
* create by zy 2019/11/28 14:58
* TODO
*/
public class WebSocketClientHandler extends SimpleChannelInboundHandler<Object> { private final WebSocketClientHandshaker handshaker;
private ChannelPromise handshakeFuture; public WebSocketClientHandler(WebSocketClientHandshaker handshaker) {
this.handshaker = handshaker;
} public ChannelFuture handshakeFuture() {
return handshakeFuture;
} @Override
public void handlerAdded(ChannelHandlerContext ctx) {
handshakeFuture = ctx.newPromise();
} @Override
public void channelActive(ChannelHandlerContext ctx) {
handshaker.handshake(ctx.channel());
} @Override
public void channelInactive(ChannelHandlerContext ctx) {
System.out.println("WebSocket Client disconnected!");
} @Override
public void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
Channel ch = ctx.channel();
if (!handshaker.isHandshakeComplete()) {
try {
//握手成功 建立连接
handshaker.finishHandshake(ch, (FullHttpResponse) msg);
System.out.println("WebSocket Client connected!");
handshakeFuture.setSuccess();
} catch (WebSocketHandshakeException e) {
//握手失败
System.out.println("WebSocket Client failed to connect");
handshakeFuture.setFailure(e);
}
return;
} if (msg instanceof FullHttpResponse) {
FullHttpResponse response = (FullHttpResponse) msg;
throw new IllegalStateException(
"Unexpected FullHttpResponse (getStatus=" + response.status() +
", content=" + response.content().toString(CharsetUtil.UTF_8) + ')');
} WebSocketFrame frame = (WebSocketFrame) msg;
if (frame instanceof TextWebSocketFrame) {
//接收客户端返回消息
TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
System.out.println("WebSocket Client received message: " + textFrame.text());
} else if (frame instanceof PongWebSocketFrame) {
System.out.println("WebSocket Client received pong");
} else if (frame instanceof CloseWebSocketFrame) {
System.out.println("WebSocket Client received closing");
ch.close();
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
cause.printStackTrace();
if (!handshakeFuture.isDone()) {
handshakeFuture.setFailure(cause);
}
ctx.close();
}
}

4.web客户端

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Netty-Websocket</title>
<script type="text/javascript">
var socket;
if(!window.WebSocket){
window.WebSocket = window.MozWebSocket;
}
if(window.WebSocket){
socket = new WebSocket("ws://127.0.0.1:9898/");
socket.onmessage = function(event){
var ta = document.getElementById('responseText');
ta.value += event.data+"\r\n";
};
socket.onopen = function(event){
var ta = document.getElementById('responseText');
ta.value = "Netty-WebSocket服务器。。。。。。连接 \r\n";
login();
};
socket.onclose = function(event){
var ta = document.getElementById('responseText');
ta.value = "Netty-WebSocket服务器。。。。。。关闭 \r\n";
};
}else{
alert("您的浏览器不支持WebSocket协议!");
}
function send(msg){
if(!window.WebSocket){return;}
if(socket.readyState == WebSocket.OPEN){
socket.send(msg);
}else{
alert("WebSocket 连接没有建立成功!");
}
}
function login(){
if(!window.WebSocket){return;}
if(socket.readyState == WebSocket.OPEN){
socket.send("建立连接成功!");
}else{
alert("WebSocket 连接没有建立成功!");
}
}
function closeSocket(){
if(!window.WebSocket){return;}
socket.close();
}
</script>
</head>
<body>
<form onSubmit="return false;">
<label>TEXT</label><input type="text" name="blaze" value="" /> <br />
<br /> <input type="button" value="发送ws消息"
onClick="send(this.form.blaze.value)" />
<hr color="black" />
<br /> <input type="button" value="断开连接"
onClick="closeSocket()" />
<hr color="black" />
<h3>服务端返回的应答消息</h3>
<textarea id="responseText" style="width: 1024px;height: 300px;"></textarea>
</form>
</body>
</html>

Netty搭建WebSocket服务端的更多相关文章

  1. Netty 搭建 WebSocket 服务端

    一.编码器.解码器 ... ... @Autowired private HttpRequestHandler httpRequestHandler; @Autowired private TextW ...

  2. 使用Netty做WebSocket服务端

    使用Netty搭建WebSocket服务器 1.WebSocketServer.java public class WebSocketServer { private final ChannelGro ...

  3. nodejs搭建简单的websocket服务端

    创建websocket服务端使用了nodejs-websocket ,首先要安装nodejs-websocket,在项目的目录下: npm install nodejs-websocket 1.搭建w ...

  4. 《用OpenResty搭建高性能服务端》笔记

    概要 <用OpenResty搭建高性能服务端>是OpenResty系列课程中的入门课程,主讲人:温铭老师.课程分为10个章节,侧重于OpenResty的基本概念和主要特点的介绍,包括它的指 ...

  5. asp.net网站作为websocket服务端的应用该如何写

    最近被websocket的一个问题困扰了很久,有一个需求是在web网站中搭建websocket服务.客户端通过网页与服务器建立连接,然后服务器根据ip给客户端网页发送信息. 其实,这个需求并不难,只是 ...

  6. C# WebSocket 服务端示例代码 + HTML5客户端示例代码

    WebSocket服务端 C#示例代码 using System; using System.Collections.Generic; using System.Linq; using System. ...

  7. contos7搭建syslog服务端与客户端

    搭建中心服务端1,编辑文件/etc/rsyslog.conf,找到以下内容,将前面的#注释符合去除#$ModLoad imtcp#$InputTCPServerRun 514 2,在/etc/rsys ...

  8. vue.js+koa2项目实战(四)搭建koa2服务端

    搭建koa2服务端 安装两个版本的koa 一.版本安装 1.安装 koa1 npm install koa -g 注:必须安装到全局 2.安装 koa2 npm install koa@2 -g 二. ...

  9. Centos6.9 搭建rsync服务端与客户端 案例:全网备份项目

    rsync的企业工作场景说明 1)定时备份 1.1生产场景集群架构服务器备份方案项目 借助cron+rsync把所有客户服务器数据同步到备份服务器 2)实时复制 本地数据传输模式(local-only ...

随机推荐

  1. golang web框架 beego 学习 (七)json转数组

    Modules type User struct { Id int64 `json:"id"` Name string `json:"name"` Email ...

  2. 第 20 课 go如何实现继承的 && 给引用模块起别名

    golang语言中没有继承,但是可以依靠组合来模拟继承和多态. package controllers import ( "encoding/json" md "gowe ...

  3. 【数据库开发】Redis消息通知

    消息通知 任务队列 使用任务队列的好处 松耦合.生产者和消费者无需知道彼此的实现细节,只需要约定好任务的描述格式.这使得生产者和消费者可以由不同的团队使用不同的编程语言编写 易于扩展.消费者可以有多个 ...

  4. Vue.js—60分钟快速入门

    本文摘自:http://www.cnblogs.com/keepfool/p/5619070.html Vue.js是当下很火的一个JavaScript MVVM库,它是以数据驱动和组件化的思想构建的 ...

  5. 502 BAD GATEWAY-k8s的cgroup限制了apache的可用内存

    1.release的组件逻辑图 2.表象:按F12,总是报502 BAD GATEWAY 3.nginx日志 [error] #: * upstream prematurely closed conn ...

  6. EMR目录

    EMR目录: E-MapReduce 是阿里云上的开源大数据平台,用户可以登录集群主节点查看相关安装路径. 登录后也可以使用 env |grep xxx 查看. 或者,在EMR Hadoop集群,切换 ...

  7. [转帖]1A2C多口充 紫米USB充电器65W桌面快充版评测

    1A2C多口充 紫米USB充电器65W桌面快充版评测 2019年10月04日 07:48 1786 次阅读 稿源:充电头网 1 条评论 https://www.cnbeta.com/articles/ ...

  8. Python【HTML基础】

    HTML基础 HTML(Hyper Text Markup Language)超文本标记语言 #HTML是一种用来描述网页的语言,HTML之于网页就好比建筑图纸之于建筑 +++++++++++++++ ...

  9. WUSOJ 1293: Fibonacci数列(Java)

    题目:

  10. Go学习路径--相关基础

    现在开始接触Go一段时间了,基本路径就是看基础学习材料,开始写项目,有问题找解决问题的方法.这里记录一下学习过程. go相关文章 Golang适合高并发场景的原因分析 go build 不同系统下的可 ...