(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的更多相关文章

  1. Netty——简单创建服务器、客户端通讯

    Netty 是一个基于NIO的客户.服务器端编程框架,使用Netty 可以确保你快速和简单的开发出一个网络应用,例如实现了某种协议的客户,服务端应用.Netty相当简化和流线化了网络应用的编程开发过程 ...

  2. Netty学习笔记(一) 实现DISCARD服务

    官方那个给出的介绍是:Netty是由JBOSS提供的一个java开源框架.Netty提供异步的.事件驱动的网络应用程序框架和工具,用以快速开发高性能.高可靠性的网络服务器和客户端程序.然后我们简单理解 ...

  3. Netty入门(一):零基础“HelloWorld”详细图文步骤

    因为接下来的项目要用到netty,所以就了解一下这个程序,奈何网上的教程都是稍微有点基础的,所以,就写一篇对于netty零基础的,顺便也记录一下. 先扔几个参考学习的网页: netty 官方API:  ...

  4. Netty 4.0 新的特性及需要注意的地方

    Netty 4.0 新的特性及需要注意的地方 这篇文章和你一起过下Netty的主发行版本的一些显著的改变和新特性,让你在把你的应用程序转换到新版本的时候有个概念. 项目结构改变 Netty的包名从or ...

  5. java架构师视频教程 内含activemq+jvm+netty+dubbo

    目录: 架构师视频教程包含activemq jvm netty dubbo 0分布式项目实战所有视频(分布式项目视频)互联网架构师第二期-视频部分互联网架构师第二期-资料部分1.Netty快速入门教程 ...

  6. Netty入门 零基础

    因为接下来的项目要用到netty,所以就了解一下这个程序,奈何网上的教程都是稍微有点基础的,所以,就写一篇对于netty零基础的,顺便也记录一下. 先扔几个参考学习的网页: netty 官方API:  ...

  7. Netty 介绍和应用场景(一)

    1.为什么选择Netty 需要了解了Socket通信(IO/NIO/AIO)编程,对于通信模型已经有了一个基本的认识.,果想把这些真正的用于实际工作中,那么还需要不断的完善.扩展和优化.比如经典的TC ...

  8. BFT-SMaRt:用Netty做客户端的可靠信道

    目录 一.Netty服务端的构建 1. 父类构造函数 ① 查找缓存 ② 相关日志 2. 服务端构造 ① 配置读取 ② 服务端配置 3. 服务端功能 ① 通用接口功能 ② Channel处理器 4. 节 ...

  9. netty第一讲 创建

    1.新建一个maven项目  https://blog.csdn.net/yanghaibobo110/article/details/73835469 2.netty是什么玩意 官方那个给出的介绍是 ...

随机推荐

  1. AWD - IDE For Web dev汉化版

    一款安卓上的HTML网页编辑软件,不错哦 下载链接 http://t.cn/AiRIvtoL

  2. pwnable.kr-echo1-Writeup

    pwnable.kr - echo1 - writeup 原文链接:https://www.cnblogs.com/WangAoBo/p/pwnable_kr_echo1.html 旧题新做,发现这道 ...

  3. 2019 ICPC南京网络赛 F题 Greedy Sequence(贪心+递推)

    计蒜客题目链接:https://nanti.jisuanke.com/t/41303 题目:给你一个序列a,你可以从其中选取元素,构建n个串,每个串的长度为n,构造的si串要满足以下条件, 1. si ...

  4. Cheapest Palindrome

    这个区间dp解的话是先知道小区间再推大区间,具体需要分类讨论当小区间已经是回文串了,下一层判断,所以一层一个呢还是一层两个呢, 下面讨论一层一个的话是什么情况,那么如果一层两个,可以在评论区写下代码供 ...

  5. C# virtual 函数

    C# virtual 是虚拟的含义,在 C# 语言中,默认情况下类中的成员都是非虚拟的,通常将类中的成员定义成虚拟的,表示这些成员将会在继承后重写其中的内容. virtual 关键字能修饰方法.属性. ...

  6. 微信小程序中showToast 提示

    icon可以none,也可以 success wx.showToast({ title: '已提交', icon: 'success', duration: 2000 })

  7. Spring - 周边设施 - H2 数据库启动时写入数据

    1. 概述 之前讲到了 H2 的引入 这下我想说说 H2 启动时的 数据导入 2. 场景 需求 启动项目后, H2 启动起来 环境数据会自动注入 H2 数据库 可以验证是否成功 3. 环境 os wi ...

  8. app内区域截图利用html2Canvals保存到手机 截屏 (html2Canvals2版本1.0.0)

    html2canvas($(], {scale:,logging:false,useCORS:true}).then(function(canvas) { var dataUrl = canvas.t ...

  9. AtCoder AGC038 C-LCMs 题解

    题目链接:https://agc038.contest.atcoder.jp/tasks/agc038_c?lang=en 题意:给定一个数组,求这个数组中所有数对的LCM之和. 分析:网上看到了很多 ...

  10. 新手学习arm的建议

    本文来自:chen4013874的博客 如果您是ARM初学者或者以前是51单片机应用开发工程师,想快速进入32位ARM嵌入式开发领域,建议您阅读本文档.本文档是我们结合多年ARM开发经验,针对初学者对 ...