netty同时实现http与socket
(1)启动类
package test; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel; /**
* netty服务器启动类
* @author songyan
*
*/
public class HttpProxyServer { public static void main(String[] args) throws Exception {
int LOCAL_PORT = (args.length > 0) ? Integer.parseInt(args[0]) : 5688;// 代理的端口号
System.out.println("Proxying on port " + LOCAL_PORT); // 主从线程组模型
EventLoopGroup bossGroup = new NioEventLoopGroup(1);
EventLoopGroup workerGroup = new NioEventLoopGroup(); try { // 创建核心类
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class) // 添加助手类
.childHandler(new ServerInitialzer()).bind(LOCAL_PORT).sync().channel().closeFuture().sync(); } finally { // 关闭主从线程
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
} }
}
(2)初始化类
package test;
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; /**
*
* @author songyan
* 通用的初始化类
*/
public class ServerInitialzer extends ChannelInitializer<SocketChannel> { @Override
protected void initChannel(SocketChannel ch) throws Exception {
ChannelPipeline pipeline = ch.pipeline(); //netty是基于http的,所以要添加http编码器
pipeline.addLast(new HttpServerCodec());
//对写大数据流的支持
pipeline.addLast(new ChunkedWriteHandler());
//设置单次请求的文件大小上限
pipeline.addLast(new HttpObjectAggregator(1024*1024*10));
//websocket 服务器处理的协议,用于指定给客户端连接访问的路由 : /ws
pipeline.addLast(new WebSocketServerProtocolHandler("/ws"));
//自定义的路由
pipeline.addLast(new HttpHandler()); } }
注:
new WebSocketServerProtocolHandler("/ws")只能拦截uri为ws://127.0.0.1:5688/ws的请求
比如我想匹配请求:ws://192.168.11.3:5688/gxgd/echo?fromUser=301208
则应该new WebSocketServerProtocolHandler("/gxgd/echo?fromUser=301208")
显然这样写是不合理的,我们的参数是不确定的,是动态的,但是如果这样写的话,是完全匹配,一点不一样就会报404。
看他的构造函数发现有
public WebSocketServerProtocolHandler(String websocketPath, boolean checkStartsWith) {
this(websocketPath, null, false, 65536, false, checkStartsWith);
}
第一个是参数是路径,第二个参数是是否startwith,也就是第二个参数设置成true就可以:只要请求是以第一个参数开头的就可以了
例如:
new WebSocketServerProtocolHandler("/gxgd/echo",true)
可以匹配
ws://192.168.11.3:5688/gxgd/echo?fromUser=301208
这样就不会出现更改参数报404的错误了
(3)自定义路由
package test; import java.time.LocalDateTime;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
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.FullHttpRequest;
import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;
import io.netty.handler.codec.http.websocketx.WebSocketFrame;
import io.netty.util.concurrent.GlobalEventExecutor; /**
* 自定义的路由 既可以实现http又可以实现socket
*
* @author songyan
*
*/
public class HttpHandler extends SimpleChannelInboundHandler<Object> {
// 用于记录和管理所有客户端的channle
private Channel outboundChannel;
private static ChannelGroup clients = new DefaultChannelGroup(GlobalEventExecutor.INSTANCE); /**
* 打开链接
*/
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
System.out.println("websocket::::::::::: active");
super.channelActive(ctx);
} /**
* 获取客户端的channle,添加到ChannelGroup中
*/
@Override
public void handlerAdded(ChannelHandlerContext ctx) throws Exception {
System.out.println("websocket::::::::::: add");
clients.add(ctx.channel());
} /**
* 从ChannelGroup中移除channel
*/
@Override
public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
System.out.println("websocket::::::::::: Removed");
} /**
* 销毁channel
*/
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
System.out.println("websocket::::::::::: destroyed");
if (clients != null) {
closeOnFlush(outboundChannel);
}
} /**
* 关闭释放channel
* @param ch
*/
static void closeOnFlush(Channel ch) {
if (ch != null && ch.isActive()) {
ch.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(ChannelFutureListener.CLOSE);
}
} @Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
} /**
* 异常捕获
*/
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
System.err.println("出错了");
cause.printStackTrace();
ctx.close();
} /**
* 路由
* 对http,websocket单独处理
*/
@Override
protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
if (msg instanceof FullHttpRequest) {// 如果是HTTP请求,进行HTTP操作
handleHttpRequest(ctx, (FullHttpRequest) msg);
} else if (msg instanceof WebSocketFrame) {// 如果是Websocket请求,则进行websocket操作
handleWebSocketFrame(ctx, (WebSocketFrame) msg);
}
} /**
* 对http请求的处理
*/
private void handleHttpRequest(ChannelHandlerContext ctx, final FullHttpRequest msg) {
final Channel inboundChannel = ctx.channel();
String host = msg.headers().get("Host");
int port = 80; String pattern = "(http://|https://)?([^:]+)(:[\\d]+)?";
Pattern r = Pattern.compile(pattern);
Matcher m = r.matcher(host);
if (m.find()) {
host = m.group(2);
port = (m.group(3) == null) ? 80 : Integer.parseInt(m.group(3).substring(1));
} Bootstrap b = new Bootstrap();
b.group(inboundChannel.eventLoop()) // use inboundChannel thread
.channel(ctx.channel().getClass()).handler(new BackendHandlerInitializer(inboundChannel)); ChannelFuture f = b.connect("127.0.0.1", 8015);
outboundChannel = f.channel();
msg.retain();
ChannelFuture channelFuture = f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
outboundChannel.writeAndFlush(msg);
} else {
inboundChannel.close();
}
}
});
} /**
* 对socket请求的处理
*/
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame msg) {
// 获取客户端传输过来的消息
String content = msg.toString();
System.out.println("websocket::: 接受到的数据:" + content);
clients.writeAndFlush(new TextWebSocketFrame("[服务器在]" + LocalDateTime.now() + "接受到消息, 消息为:" + content)); } }
netty同时实现http与socket的更多相关文章
- Netty——简单创建服务器、客户端通讯
Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用.Netty相当简化和流线化了网络应用的编程开发过程 ...
- Netty学习笔记(一) 实现DISCARD服务
官方那个给出的介绍是:Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.然后我们简单理解 ...
- Netty入门(一):零基础“HelloWorld”详细图文步骤
因为接下来的项目要用到netty,所以就了解一下这个程序,奈何网上的教程都是稍微有点基础的,所以,就写一篇对于netty零基础的,顺便也记录一下. 先扔几个参考学习的网页: netty 官方API: ...
- Netty 4.0 新的特性及需要注意的地方
Netty 4.0 新的特性及需要注意的地方 这篇文章和你一起过下Netty的主发行版本的一些显著的改变和新特性,让你在把你的应用程序转换到新版本的时候有个概念. 项目结构改变 Netty的包名从or ...
- java架构师视频教程 内含activemq+jvm+netty+dubbo
目录: 架构师视频教程包含activemq jvm netty dubbo 0分布式项目实战所有视频(分布式项目视频)互联网架构师第二期-视频部分互联网架构师第二期-资料部分1.Netty快速入门教程 ...
- Netty入门 零基础
因为接下来的项目要用到netty,所以就了解一下这个程序,奈何网上的教程都是稍微有点基础的,所以,就写一篇对于netty零基础的,顺便也记录一下. 先扔几个参考学习的网页: netty 官方API: ...
- Netty 介绍和应用场景(一)
1.为什么选择Netty 需要了解了Socket通信(IO/NIO/AIO)编程,对于通信模型已经有了一个基本的认识.,果想把这些真正的用于实际工作中,那么还需要不断的完善.扩展和优化.比如经典的TC ...
- BFT-SMaRt:用Netty做客户端的可靠信道
目录 一.Netty服务端的构建 1. 父类构造函数 ① 查找缓存 ② 相关日志 2. 服务端构造 ① 配置读取 ② 服务端配置 3. 服务端功能 ① 通用接口功能 ② Channel处理器 4. 节 ...
- netty第一讲 创建
1.新建一个maven项目 https://blog.csdn.net/yanghaibobo110/article/details/73835469 2.netty是什么玩意 官方那个给出的介绍是 ...
随机推荐
- 每天进步一点点------verilog语言实现的分频
一 .占空比50%的任意奇数分频 如果要实现占空比为50%的三分频时钟,可以通过待分频时钟下降沿触发计数,和上升沿同样的方法计数进行三分频,然后下降沿产生的三分频时钟和上升沿产生的时钟进行相或运算,即 ...
- Bridge(Ad Hoc)
- css3之渐变背景色(linear-gradient)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- PyQt5遇到的一个坑 "ImportError: unable to find Qt5Core.dll on PATH" 及解决办法
最近再实现一个功能,主要是将自动化测试界面化 环境组合为:Windows 64bit + PyCharm + Python + PyQt5 + Pyinstaller + Inno Setup PS ...
- SQL查询语句的执行
执行过程 连接器 - 管理连接,权限验证 查询缓存 - 命中缓存直接返回结果 分析器 - 词法分析 ,语法分析 优化器 - 分析执行计划,选择最优的执行计划 执行器 - 操作存储引擎接口,返回结果 不 ...
- UNICODE编码UTF-16 中的Endian(FE FF) 和 Little Endian(FF FE)
从网上找到的两篇不错的文章,由于被网上多处转载,所以不知道源处,未能注明出处,希望作者见谅,如有意见请发信给我,谢谢! 第一篇很清晰. 介绍Unicode之前,首先要讲解一些基础知识.虽然跟Unico ...
- 【Webex】加入会议是无法正常加入!提示“下载会议组件时无法获取正确的参数。 请联系技术支持以获取帮助。
来自:Cisco Webex帮助中心 https://help.webex.com/zh-cn/WBX9000023909/Error-Failed-to-get-correct-parameters ...
- 1.2、初识WebRTC
文章导读:本节内容,如标题所讲,“初识webrtc”.读完之后,我需要你能清楚三个问题:第一.真正的搞明白实时音视频在生产环境中的真实应用以及前景分析:第二.开发一个符合商业标准的实时音视频应用需要解 ...
- 题解【洛谷P5436】【XR-2】缘分
题目背景 世间万物都置身于缘分编织的大网中.缘分未到,虽历经千劫,却不能相遇.缘分到了,在草原上都能等到一艘船.--<一禅小和尚> 题目描述 一禅希望知道他和师父之间的缘分大小.可是如何才 ...
- socket udp编程的一些积累的记录
接了个小活,要求写udp的客户端,循环接收服务端的固定的指令并显示数据 我设计的逻辑是,用户在界面输入框输入服务器ip.端口,随后udp连接,开启线程循环接收,接收指令,解析成数据,存在结构体的lis ...