服务端:

引入Netty依赖

        <!-- netty -->
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.27.Final</version>
</dependency>

WebSocket全局配置类的编写

/**
* 存储整个工程的全局配置
*/
public class NettyConfig { /**
* 存储每一个客户端接入进来时的channel对象
*/
public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); }

接收/处理/响应客户端websocket请求的核心业务处理类

package com.imooc.netty;

import java.util.Date;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
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.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.websocketx.CloseWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PingWebSocketFrame;
import io.netty.handler.codec.http.websocketx.PongWebSocketFrame;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshaker;
import io.netty.handler.codec.http.websocketx.WebSocketServerHandshakerFactory;
import io.netty.util.CharsetUtil; /**
* 接收/处理/响应客户端websocket请求的核心业务处理类
*/
public class MyWebSocketHandler extends SimpleChannelInboundHandler<Object> { private WebSocketServerHandshaker handshaker;
private static final String WEB_SOCKET_URL = "ws://localhost:8888/websocket"; /**
* 客户端与服务端创建连接的时候调用
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
NettyConfig.group.add(ctx.channel());
System.out.println("客户端与服务端连接开启...");
} /**
* 客户端与服务端断开连接的时候调用
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
NettyConfig.group.remove(ctx.channel());
System.out.println("客户端与服务端连接关闭...");
} /**
* 服务端接收客户端发送过来的数据结束之后调用
*/
@Override
public void channelReadComplete(ChannelHandlerContext ctx) throws Exception {
ctx.flush();
} /**
* 工程出现异常的时候调用
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
cause.printStackTrace();
ctx.close();
} /**
* 服务端处理客户端websocket请求的核心方法
*/
protected void channelRead0(ChannelHandlerContext context, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {
// 处理客户端向服务端发起http握手请求的业务
this.handHttpRequest(context, (FullHttpRequest) msg);
}else if (msg instanceof WebSocketFrame) {
// 处理websocket连接业务
this.handWebsocketFrame(context, (WebSocketFrame) msg);
}
} /**
* 处理客户端与服务端之前的websocket业务
*/
private void handWebsocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame){
// 判断是否是关闭websocket的指令
if (frame instanceof CloseWebSocketFrame) {
handshaker.close(ctx.channel(), (CloseWebSocketFrame)frame.retain());
} // 判断是否是ping消息
if (frame instanceof PingWebSocketFrame) {
ctx.channel().write(new PongWebSocketFrame(frame.content().retain()));
return;
} // 判断是否是二进制消息,如果是二进制消息,抛出异常
if (!(frame instanceof TextWebSocketFrame)){
System.out.println("目前我们不支持二进制消息");
throw new RuntimeException("【"+this.getClass().getName()+"】不支持消息");
} // 返回应答消息
// 获取客户端向服务端发送的消息
String request = ((TextWebSocketFrame) frame).text();
System.out.println("服务端收到客户端的消息====>>>" + request);
TextWebSocketFrame tws = new TextWebSocketFrame(new Date().toString() + ctx.channel().id() + " ===>>> " + request);
// 群发,服务端向每个连接上来的客户端群发消息
NettyConfig.group.writeAndFlush(tws);
}
/**
* 处理客户端向服务端发起http握手请求的业务
*/
private void handHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req){
if (!req.decoderResult().isSuccess() || !("websocket".equals(req.headers().get("Upgrade")))) {
this.sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));
return;
}
WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(WEB_SOCKET_URL, null, false);
handshaker = wsFactory.newHandshaker(req);
if (handshaker == null) {
WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());
}else{
handshaker.handshake(ctx.channel(), req);
}
} /**
* 服务端向客户端响应消息
*/
private void sendHttpResponse(ChannelHandlerContext ctx, FullHttpRequest req,
DefaultFullHttpResponse res){
if (res.status().code() != 200) {
ByteBuf buf = Unpooled.copiedBuffer(res.status().toString(), CharsetUtil.UTF_8);
res.content().writeBytes(buf);
buf.release();
}
// 服务端向客户端发送数据
ChannelFuture f = ctx.channel().writeAndFlush(res);
if (res.status().code() != 200) {
f.addListener(ChannelFutureListener.CLOSE);
}
} }

WebSocket初始化连接时各个组件的类实现

package com.imooc.netty;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler; /**
* 初始化连接时候的各个组件
*/
public class MyWebSocketChannelHandler extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel e) throws Exception {
e.pipeline().addLast("http-codec", new HttpServerCodec());
e.pipeline().addLast("aggregator", new HttpObjectAggregator(65536));
e.pipeline().addLast("http-chunked", new ChunkedWriteHandler());
e.pipeline().addLast("handler", new MyWebSocketHandler());
} }

WebSocket启动类的编写

package com.imooc.netty;

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; /**
* 程序的入口,负责启动应用
*/
public class Main { public static void main(String[] args) {
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workGroup);
b.channel(NioServerSocketChannel.class);
b.childHandler(new MyWebSocketChannelHandler());
System.out.println("服务端开启等待客户端连接....");
Channel ch = b.bind(8888).sync().channel();
ch.closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally{
// 退出程序
bossGroup.shutdownGracefully();
workGroup.shutdownGracefully();
}
} }

客户端

编写客户端页面

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset = utf-8"/>
<title>WebSocket客户端</title>
<script type="text/javascript">
var socket;
if(!window.WebSocket){
window.WebSocket = window.MozWebSocket;
} if(window.WebSocket){
socket = new WebSocket("ws://localhost:8888/websocket");
socket.onmessage = function(event){
var ta = document.getElementById('responseContent');
ta.value += event.data + "\r\n";
}; socket.onopen = function(event){
var ta = document.getElementById('responseContent');
ta.value = "你当前的浏览器支持WebSocket,请进行后续操作\r\n";
}; socket.onclose = function(event){
var ta = document.getElementById('responseContent');
ta.value = "";
ta.value = "WebSocket连接已经关闭\r\n";
};
}else{
alert("您的浏览器不支持WebSocket");
} function send(message){
if(!window.WebSocket){
return;
}
if(socket.readyState == WebSocket.OPEN){
socket.send(message);
}else{
alert("WebSocket连接没有建立成功!!");
}
}
</script>
</head>
<body>
<form onSubmit="return false;">
<input type = "text" name = "message" value = ""/>
<br/><br/>
<input type = "button" value = "发送WebSocket请求消息" onClick = "send(this.form.message.value)"/>
<hr color="red"/>
<h2>客户端接收到服务端返回的应答消息</h2>
<textarea id = "responseContent" style = "width:1024px; height:300px"></textarea>
</form>
</body>
</html>

测试

启动服务端,然后打开客户端页面

客户端向服务端发送WebSocket消息,观察结果

服务端控制台:

关闭服务端

【Netty】Netty入门之WebSocket小例子的更多相关文章

  1. 1、Netty 实战入门详解

    一.Netty 简介 Netty 是基于 Java NIO 的异步事件驱动的网络应用框架,使用 Netty 可以快速开发网络应用,Netty 提供了高层次的抽象来简化 TCP 和 UDP 服务器的编程 ...

  2. 网络应用框架Netty快速入门

    一 初遇Netty Netty是什么? Netty 是一个提供 asynchronous event-driven (异步事件驱动)的网络应用框架,是一个用以快速开发高性能.可扩展协议的服务器和客户端 ...

  3. Selenium WebDriver + Grid2 + RSpec之旅(三) ----入门小例子

    Selenium WebDriver + Grid2 + RSpec之旅(三) ----入门小例子 第一个例子都是比较简单的博客园登录界面,就像学习编程语言时候都是从Hello,World!开始. 1 ...

  4. 一个有趣的小例子,带你入门协程模块-asyncio

    一个有趣的小例子,带你入门协程模块-asyncio 上篇文章写了关于yield from的用法,简单的了解异步模式,[https://www.cnblogs.com/c-x-a/p/10106031. ...

  5. webcat——基于netty的http和websocket框架

    代码地址如下:http://www.demodashi.com/demo/12687.html Webcat是一个基于netty的简单.高性能服务端框架,目前提供http和websocket两种协议的 ...

  6. 基于vue-cli、elementUI的Vue超简单入门小例子

    - 这个例子还是比较简单的,独立完成后,能大概知道vue是干嘛的,可以写个todoList的小例子. - 开始写例子之前,先对环境的部署做点简单的介绍,其实和Vue官方的差不多. #如若没有安装过vu ...

  7. Netty 框架学习 —— 添加 WebSocket 支持

    WebSocket 简介 WebSocket 协议是完全重新设计的协议,旨在为 Web 上的双向数据传输问题提供一个切实可行的解决方案,使得客户端和服务器之间可以在任意时刻传输消息 Netty 对于 ...

  8. springmvc入门的第一个小例子

    今天我们探讨一下springmvc,由于是初学,所以简单的了解一下 springmvc的流程,后续会持续更新... 由一个小例子来简单的了解一下 springmvc springmvc是spring框 ...

  9. Ajax入门小例子

    大牛文章:http://www.cnblogs.com/guduoduo/p/3681296.html                               ---Ajax基础学习 http:/ ...

随机推荐

  1. eclipse中安装lombok插件

    一:下载lombok 下载地址:https://projectlombok.org/downloads/lombok.jar 或者访问官网下载  https://projectlombok.org/ ...

  2. css3实现钟表效果

    利用css3 transform属性刻画钟表的的刻度以及指针的角度,代码如下: <head> <meta charset="UTF-8"> <titl ...

  3. CSS3学习-用CSS制作立体导航栏

    <!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. countUp 动画展示数字变化

    html <p id="countUp" style="font-size:25px;height:25px;background-color:#0aa;" ...

  5. SQL SERVER之填充因子

    建SQL SERVER索引的时候有一个选项,即Fillfactor(填充因子). 这个可能很少人会去注意它,但它也是比较重要的.大家可能也都知道有这个东西,但是如何去使用它,可能会比较迷糊.另外,即使 ...

  6. 使用jmeter测试数据库性能

    出现如图所示的问题 解决办法: 1.下载驱动包,将mysql-connector-Java.jar分别放到Jmeter和Java安装目录的lib和ext目录下 链接:http://pan.baidu. ...

  7. python基础教程总结15——6 CGI远程编辑

    功能: 将文档作为普通网页显示: 在web表单的文本域内显示文档: 保存表单中的文本: 使用密码保护文档: 容易拓展,支持处理多余一个文档的情况 1.CGI CGI(Comment Gateway I ...

  8. 2018.3.11 Java DEBUG 调试的方法

    F5:Step Into:跳进当前执行的方法中 F6:Step Over:跳过该行继续执行 F7:Step Return:从方法中跳出继续执行 F8:Resume:全部运行通过,从调试状态恢复 Ctr ...

  9. 分类回归树(CART)

    概要 本部分介绍 CART,是一种非常重要的机器学习算法.   基本原理   CART 全称为 Classification And Regression Trees,即分类回归树.顾名思义,该算法既 ...

  10. 拨出网线后,网卡IP丢失

    /etc/network/interfaces与NetworkManager 问题:在Centos7上把网线拨出后,发现网卡状态是down,并且网卡上的IP丢失 原因:此网卡被NetworkManag ...