(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. python-第三方库的理解及某个函数的源代码

    第三方库,是一个总称,里面有各个模块,而具体使用的函数是模块里的. 库包含多个模块, 每个模块里包含多个函数. import AAAA     就是引用AAAA这个库,这个库里的模块函数都可以用,只是 ...

  2. A. DZY Loves Chessboard

    DZY loves chessboard, and he enjoys playing with it. He has a chessboard of n rows and m columns. So ...

  3. C 语言实例 - 约瑟夫生者死者小游戏

    30 个人在一条船上,超载,需要 15 人下船. 于是人们排成一队,排队的位置即为他们的编号. 报数,从 1 开始,数到 9 的人下船. 如此循环,直到船上仅剩 15 人为止,问都有哪些编号的人下船了 ...

  4. 学会C#可以做什么

    C#基于.NET Framework  和 .NET CORE平台 Client/Server 客户端/服务端 windows桌面应用程序 winform  2D WPF  3D Browser/Se ...

  5. 单选按钮 设置required属性无法进行非空验证

    先看代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF ...

  6. 使用Spring框架整合Java Mail

    我的博客名为黑客之谜,今天演示的案例中会出现我的邮箱,还不赶紧收藏!我现在是小白,但是随着时间的流逝,我会逐渐向大神走进,所以,喜欢我的,或者喜欢大神的,点一波关注吧!顺便说一下,双十二快到了,有什么 ...

  7. malloc实现机制

    使用过c语言的都知道malloc是一个动态分配内存的函数,还可以通过free释放内存空间. 如果我们想分析一下malloc的源码,这其实不是一会就能看懂的,但是我们可以讨论一下malloc的简单实现. ...

  8. Linux下查看当前文件大小的命令

    1.ls -lht 列出每个文件的大小和当前目录所有文件大小总和 2.du -sh * 列出当前文件夹下的所有子文件的大小 看你需要啥样的,自己来吧

  9. Ip2Region IP转化地址位置

    Ip2Region有中文和数据结构支持,是一个很好的第三方ip转换工具. java: <dependency> <groupId>org.lionsoul</groupI ...

  10. html学习3-CSS补充

    position fixed:把标签固定在页面的某处 例子:使用fixed制作“回到顶部”按钮 <!DOCTYPE html> <html lang="en"&g ...