(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. 2019HDU多校第一场1001 BLANK (DP)(HDU6578)

    2019HDU多校第一场1001 BLANK (DP) 题意:构造一个长度为n(n<=10)的序列,其中的值域为{0,1,2,3}存在m个限制条件,表示为 l r x意义为[L,R]区间里最多能 ...

  2. 配置yum仓库:yum install 软件

    1.一个重要模板: 进入/etc/yum.repos.d文件夹,新建一个xiaoxu.repo文件,其中xiaoxu可以根据需要来取名. [模板] vim  xiaoxu.repo [rhel]    ...

  3. Redis 基本数据类型以及相应操作

    〇.常用命令 select <num> 选择库0~15 默认0号库 key * 查看当前库所有键(可以接正则表达式) exists <key> type <key> ...

  4. java &&和&与逻辑运算区别

    二者都表示与运算,同真为真,遇假即假 && 具有短路功能,前面为false后面不在预算直接表达式为false; &还可以用作位运算符,当&操作符两边的表达式不是 boo ...

  5. 一些常用的js代码

    跳转 window.location.href= 刷新  location.reload()

  6. HTML入门归纳--JavaScript

    本人一直在从事.net的开发,界面都是采用的WPF,近期花了一个多月进行HTML前端的学习,在这里呢进行学习总结和归纳. 本系列将主要分为4个模块: 控件 样式 布局 JavaScript 根据多年W ...

  7. [lua]紫猫lua教程-命令宝典-L1-01-05. if判断结构

    L1[if]01. 简单的if判断结构 没什么说得 if得基本结构如下 xxx= ) then testlib.traceprint("1-100") ) then testlib ...

  8. 003 CSS汇总

    字体属性:(font) 大小 {font-size: x-large;}(特大) xx-small;(极小) 一般中文用不到,只要用数值就可以,单位:PX.PD 样式 {font-style: obl ...

  9. Day0 认识Java与变量类型

    字节码与虚拟机 Java介于编译型语言和解释型语言之间.编译型语言如C.C++,代码是直接编译成机器码执行,但是不同的平台(x86.ARM等)CPU的指令集不同,因此,需要编译出每一种平台的对应机器码 ...

  10. 设备驱动基础学习--platform driver简单实现

    platform是一条虚拟的总线.设备用platform_device表示,驱动用platform_driver进行注册,Linux platform driver机制和传统的device drive ...