java netty html_源码时代JAVA干货分享|带你用Netty框架实现WebSocket通信

功能介绍Netty开发服务器

HTML实现客户端

实现服务端与客户端时实时交互

开发步骤

1.导包

io.netty

netty‐all

5.0.0.Alpha2

2.工程配置文件:NettyConfig

/**

* 这里放的是工程中相应的配置

*/

public class NettyConfig{

/**

* 用于存储每一个客户端接入进来时的channel对象

*/

public static ChannelGroup group = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE);

}

3.MyWebSocketHandler

public class MyWebSocketHandler extends SimpleChannelInboundHandler { private WebSocketServerHandshaker handshaker;

//请求路径

private static final String WEB_SOCKET_URL = "ws://localhost:8888/websocket";

//工程出现异常的时候调用@Override

public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {

cause.printStackTrace(); ctx.close(); //关闭当前连接

}

//客户端与服务器创建连接的时候调用@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(); //进行数据清除

}

//服务端处理客户端调用的核心方法

protected void messageReceived(ChannelHandlerContext context, Object msg) throws Exception {

//处理客户端向服务端发起http握手请求业务if(msg instanceof FullHttpRequest){

handHttpRequest(context,(FullHttpRequest) msg);

}else if(msg instanceof WebSocketFrame){

//处理websocket连接业务handWebSocketFrme(context,(WebSocketFrame)msg);

}

}

/**

* 处理客户端与服务端之前的websocket业务

* @param ctx

* @param frame

*/

private void handWebSocketFrme(ChannelHandlerContext ctx,WebSocketFrame frame){

//判断是否是关闭websocket的指令

if(frame instanceof CloseWebSocketFrame){ handshaker.close(ctx.channel(),((CloseWebSocketFrame) frame).retain());

}

//判断是否是Ping消息

if(frame instanceof PingWebSocketFrame){

//返回一个胖信息

ctx.channel().write(newPongWebSocketFrame(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握手请求的业务

* @param ctx

* @param req

*/

private void handHttpRequest(ChannelHandlerContext ctx,FullHttpRequest req){

// req.headers().get()

// req.decoderResult().isSuccess()

//不是websocket,就不是客户端发给服务器的Http请求if(!req.decoderResult().isSuccess()|| !

("websocket").equals(req.headers().get("Upgrade"))){

sendHttpResponse(ctx,req,new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST));

return;

}

WebSocketServerHandshakerFactory wsFactory =

newWebSocketServerHandshakerFactory(WEB_SOCKET_URL,null,false); handshaker = wsFactory.newHandshaker(req);

if(handshaker==null){

WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel());

}else{

handshaker.handshake(ctx.channel(),req);

}

}

/**

* 服务端向客户端响应消息

* @param ctx

* @param req

* @param res

*/

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);

}

}

}

4 初始化连接各个组件:MyWebSocketChannelHandler

/**

* 初始化连接各个组件

*/

public class MyWebSocketChannelHandlerextends ChannelInitializer{

protected void initChannel(SocketChannel e) throws Exception { e.pipeline().addLast("http‐codec",new HttpServerCodec()); e.pipeline().addLast("aggregator",new HttpObjectAggregator(66636)); e.pipeline().addLast("http‐chunked",new ChunkedWriteHandler()); e.pipeline().addLast("handler",new MyWebSocketHandler());

}

}

5 程序入口

/**

* 程序的入口,负责启动应用

*/

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();

}

}

}

6 web端测试代码

WebSocket客户端

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("responseContext"); ta.value += event.data +"\r\n";

}

socket.onopen = function (event) {

var ta = document.getElementById("responseContext"); ta.value = "您浏览器支持webSoceket,请进行后续 操作\r\n";

}

socket.onclose = function (event) {

var ta = document.getElementById("responseContext"); ta.value = "";

ta.value = "webSoceket连接已经关闭";

}

}else{

console.debug("浏览器不支持webSocket")

}

function send() {

var message = document.getElementById("message").value; if(!window.WebSocket){

return;

}

if(socket.readyState == WebSocket.OPEN){ socket.send(message)

}else{

alert("连接没有建立成功!");

}

}


客户端接收到服务端返回的消息

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/355659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用Apache Drill REST API通过Node构建ASCII仪表板

Apache Drill有一个隐藏的瑰宝:易于使用的REST接口。 该API可用于查询,分析和配置Drill引擎。 在此博客文章中,我将说明如何使用Brilled Contrib使用Drill REST API创建ascii仪表板。 ASCII仪表盘如下所示: 先决条件 Node.js …

mysql+cast+0x_mysql cast与convert 函数的用法

MySQL 的CAST()和CONVERT()函数可用来获取一个类型的值,并产生另一个类型的值。两者具体的语法如下:CAST(value as type);CONVERT(value, type);就是CAST(xxx AS 类型), CONVERT(xxx,类型)。可以转换的类型是有限制的。这个类型可以是以下值其中的一个&a…

影子场vs.属性访问器接口第2轮

如果你们还没有注意到Dirk Lemmerman和我之间的(轻松) 对决 ,那么让我快速提及一下我们是如何做到这一点的。 首先,Dirk创建了JavaFX技巧23:“ 为属性保存内存阴影字段 ”,以帮助应用程序开发人员在使用Jav…

java wmi远程桌面服务器_WMI实现远程监控多台windows服务器

简介WMI简介:WMI(Windows Management Instrumentation,Windows 管理规范)是一项核心的 Windows 管理技术;用户可以使用 WMI 管理本地和远程计算机。WQL简介:WQL就是WMI中的查询语言,WQL的全称是WMI Query Language,简称…

如何:在Spring中使用@Conditional和Condition注册组件

Spring中的Profile批注可以用于任何自动检测候选的Spring组件(例如, Service Component, Service Component , Service Configuration等)。 Profile批注接受单个配置文件或一组必须是活动的配置文件,以使带…

java joda_java-Jodatime的开始时间和结束时间

对于那些来这里寻找“ js-joda”答案的人,您有两种选择,具体取决于要完成的工作选项1:您希望同一时区的一天开始由于您已选择根据与时区相关的即时时间来计算时间,因此应使用ZonedDateTime:import { ZonedDateTime, Lo…

Lowest Common Ancestor of a Binary Search Tree a Binary Tree

235. Lowest Common Ancestor of a Binary Search Tree 题目链接:https://leetcode.com/problems/lowest-common-ancestor-of-a-binary-search-tree/#/description 题目大意:给定一棵二叉查找树和两个节点p和q,要求返回这两个节点的第一个公共…

perl java_与Perl相比Java性能问题

我已经编写了一个Perl代码来处理大量CSV文件并获取输出,这需要0.8326秒才能完成.my $opname $ARGV[0];my files find . -name "*${opname}*.csv";mtime -10 -type f;my %hash;foreach my $file (files) {chomp $file;my $time $file;$time ~ s/.*\~(.*?)\..*/$1/…

controller调用另一个controller中的方法 获取返回值_必须掌握!你知道 Spring 中运用的 9 种设计模式吗 ?...

Spring中涉及的设计模式总结,在面试中也会经常问道 Spring 中设计模式的问题。本文以实现方式、实质、实现原理的结构简单介绍 Sping 中应用的 9 种设计模型,具体详细的刨析会在后面的文章发布,话不多说,来个转发、在看、收藏三连…

我个人的CRUD故事-或我如何来到CUBA平台

在此博客文章中,我想介绍一下我如何使用CUBA平台以及此工具的好处。 在我年轻的“业务应用程序开发”历史上,我将深入探讨不同的阶段,只为您提供一些背景知识。 因此,让我们从如何进入典型的CRUD应用程序开始,以帮助非…

MySQL分库分表环境下全局ID生成方案

转自:https://my.oschina.net/u/142836/blog/174465 在大型互联网应用中,随着用户数的增加,为了提高应用的性能,我们经常需要对数据库进行分库分表操作。在单表时代,我们可以完全依赖于数据库的自增ID来唯一标识一个用…

java 不定参数方法_java中不定长参数的使用方法

java中不定长参数的使用方法不定长参数方法的语法如下:返回值 方法名(参数类型...参数名称)在参数列表中使用“...”形式定义不定长参数,其实这个不定长参数a就是一个数组,编译器会将(int...a)这种形式看作是(int[] a)的形式。示例&#xff1…

光盘刻录只允许读取不能拷贝_原来 8 张图,就可以搞懂「零拷贝」了

作者 | 小林coding来源 | 小林coding(ID:CodingLin)前言磁盘可以说是计算机系统最慢的硬件之一,读写速度相差内存 10 倍以上,所以针对优化磁盘的技术非常的多,比如零拷贝、直接 I/O、异步 I/O 等等,这些优化的目的就是…

如何:带有Thymeleaf和Spring Boot的Java 8日期和时间

如果您碰巧使用Spring Boot和Thymeleaf,并且需要在视图中格式化Java 8 Date&Time对象,则可以使用thymeleaf-extras-java8time –用于Java 8 Date&Time API的Thymeleaf模块。 向现有的基于Maven或Gradle的Spring Boot项目中添加th…

纯java分布式内存数据库_最新Java岗面试清单:分布式+Dubbo+线程+Redis+数据库+JVM+并发...

最近可能有点闲的慌,没事就去找面试面经,整理了一波面试题。我大概是分成了Java基础、中级、高级,分布式,Spring架构,多线程,网络,MySQL,Redis缓存,JVM相关,调…

c++ 多核cpu序列号_详解CPU几个重点基础知识

作者 | 骏马金龙责编 | 阿秃关于CPU和程序的执行1、程序的运行过程,实际上是程序涉及到的、未涉及到的一大堆的指令的执行过程。当程序要执行的部分被装载到内存后,CPU要从内存中取出指令,然后指令解码(以便知道类型和操作数,简单…

5.8上午

数学分册基础概念 转载于:https://www.cnblogs.com/yanyuying/p/6828791.html

java log4j 写日志_Java log4j同时写入文本日志和数据库日志

版权声明:转载原创文章请以超链接形式请注明原文章出处,尊重作者,尊重原创!恰饭广告Log4jUtil.javaimport org.apache.log4j.Logger;import org.apache.log4j.MDC;public class Log4jUtil {private static Logger logger Logger.…

订单生产计划表范本_工厂生产管理为什么需要ERP软件?

对于工厂来说,规模大了,管理问题也就随之多了,在工厂生产流程中,我们常见的一些生产现象,比如生产计划表徒具形式、各生产部门半成品堆积、生产计划达标率低、前后工序原材料或半成品衔接不上、经常追加或取消生产计划…

codeforces 701 E. Connecting Universities(树+ 边的贡献)

题目链接:http://codeforces.com/contest/701/problem/E 题意:有n个城市构成一棵树,一个城市最多有一个学校,这n个城市一共2*k个学校,要对这2*k个学校进行连边,使得所有连出来的边的和最大,每条…