HTTP(超文本传输协议)协议是建立在TCP传输协议之上的应用层协议,它的发展是万维网协会和Internet工作小组IETF合作的结果。HTTP是一个属于应用层的面向对象的协议,由于其简洁、快速的方式,适用于分布式超媒体信息系统。它于1990年提出,经过多年的使用和发展,得到了不断的完善和扩展。本文将介绍如何基于Netty 的HTTP协议栈进行HTTP服务端和客户端的开发。由于Netty的HTTP协议栈是基于Netty的NIO通信框架开发的,因此,Netty的HTTP协议也是异步非阻塞的。
HTTP服务端开发
HttpFileServer.java
package emulator.http; import emulator.Constants; import io.netty.bootstrap.ServerBootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestDecoder; import io.netty.handler.codec.http.HttpResponseEncoder; import io.netty.handler.stream.ChunkedWriteHandler; /** * 模拟服务端 * @author lh * @date 2015-08-11 14:33 * @version 1.0 * */ public class HttpFileServer { public void run(final int port) throws Exception { EventLoopGroup bossGroup = new NioEventLoopGroup(); EventLoopGroup workerGroup = new NioEventLoopGroup(); try { ServerBootstrap b = new ServerBootstrap(); b.group(bossGroup, workerGroup) .channel(NioServerSocketChannel.class) .childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) throws Exception { // 服务端,对请求解码 ch.pipeline().addLast("http-decoder", new HttpRequestDecoder()); // 聚合器,把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536)); // 服务端,对响应编码 ch.pipeline().addLast("http-encoder", new HttpResponseEncoder()); // 块写入处理器 ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); // 自定义服务端处理器 ch.pipeline().addLast("fileServerHandler", new HttpFileServerHandler()); } }); ChannelFuture future = b.bind(Constants.DEFAULT_IP, port).sync(); System.out.println("HTTP文件目录服务器启动,网址是 : " + "http://" + Constants.DEFAULT_IP + ":" + port); future.channel().closeFuture().sync(); } finally { bossGroup.shutdownGracefully(); workerGroup.shutdownGracefully(); } } public static void main(String[] args) throws Exception { new HttpFileServer().run(Constants.DEFAULT_PORT); } }
HttpFileServerHandler.java
package emulator.http; import static io.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE; import static io.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import java.io.File; import java.io.IOException; import org.apache.commons.io.FileUtils; import emulator.Constants; import emulator.util.Dom4JUtil; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelFutureListener; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.util.CharsetUtil; /** * 模拟服务端处理器 * @author lh * @date 2015-08-11 14:33 * @version 1.0 * */ public class HttpFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest> { @Override public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST); return; } ByteBuf buf = request.content(); byte [] req = new byte[buf.readableBytes()]; buf.readBytes(req); String xml = new String(req,"UTF-8"); resp(ctx,xml); } /** * * @param xml */ private void resp(ChannelHandlerContext ctx, String xml){ String transCode = Dom4JUtil.header(xml, "transcode"); String retUrl = "D:\\workspaces\\eclipse-huifu\\emulator\\xml\\error.xml"; String retCtt = null; if(equal(transCode, Constants.TC_DZZH)){//电子账户 retUrl = "D:\\workspaces\\eclipse-huifu\\emulator\\xml\\account\\manage\\resp.xml"; }else if(equal(transCode, Constants.TC_YHKBD)){//银行卡绑定 } try { retCtt = FileUtils.readFileToString(new File(retUrl)); } catch (IOException e) { e.printStackTrace(); } FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FOUND, Unpooled.copiedBuffer(retCtt, CharsetUtil.UTF_8)); response.headers().set(CONTENT_TYPE, "text/xml; charset=UTF-8"); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } public static boolean equal(String var, String cons){ return isNotEmpty(var) && cons.equals(var); } private static boolean isNotEmpty(String s){ return (null != s && !"".equals(s)); } /** * 错误处理 * @param ctx * @param status */ private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) { String ret = null; FullHttpResponse response = new DefaultFullHttpResponse(HTTP_1_1, status, Unpooled.copiedBuffer(ret, CharsetUtil.UTF_8)); response.headers().set(CONTENT_TYPE, "text/xml; charset=UTF-8"); ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { ctx.close(); cause.printStackTrace(); } }
HTTP客户端开发
HttpFileClient.java
package emulator.http; import io.netty.bootstrap.Bootstrap; import io.netty.channel.ChannelFuture; import io.netty.channel.ChannelInitializer; import io.netty.channel.ChannelOption; import io.netty.channel.EventLoopGroup; import io.netty.channel.nio.NioEventLoopGroup; import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; import io.netty.handler.codec.http.HttpObjectAggregator; import io.netty.handler.codec.http.HttpRequestEncoder; import io.netty.handler.codec.http.HttpResponseDecoder; import io.netty.handler.stream.ChunkedWriteHandler; import java.net.InetSocketAddress; import emulator.Constants; /** * 模拟客户端 * * @author lh * @date 2015-08-11 14:31 * @version 1.0 * */ public class HttpFileClient { public void connect(int port) throws Exception { // 配置客户端NIO线程组 EventLoopGroup group = new NioEventLoopGroup(); try { Bootstrap b = new Bootstrap(); b.group(group).channel(NioSocketChannel.class) .option(ChannelOption.TCP_NODELAY, true) .handler(new ChannelInitializer<SocketChannel>() { @Override public void initChannel(SocketChannel ch) throws Exception { // 客户端,对请求编码 ch.pipeline().addLast("http-encoder", new HttpRequestEncoder()); // 客户端,对响应解码 ch.pipeline().addLast("http-decoder", new HttpResponseDecoder()); // 聚合器,把多个消息转换为一个单一的FullHttpRequest或是FullHttpResponse ch.pipeline().addLast("http-aggregator", new HttpObjectAggregator(65536)); // 块写入处理器 ch.pipeline().addLast("http-chunked", new ChunkedWriteHandler()); // 自定义客户端处理器 ch.pipeline().addLast("fileClientHandler", new HttpFileClientHandler()); } }); // 发起异步连接操作 ChannelFuture f = b.connect(new InetSocketAddress(port)).sync(); // 当代客户端链路关闭 f.channel().closeFuture().sync(); } finally { // 优雅退出,释放NIO线程组 group.shutdownGracefully(); } } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { new HttpFileClient().connect(Constants.DEFAULT_PORT); } }
HttpFileClientHandler.java
package emulator.http; import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1; import java.io.File; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.apache.commons.io.FileUtils; import emulator.Constants; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.SimpleChannelInboundHandler; import io.netty.handler.codec.http.DefaultFullHttpRequest; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.FullHttpResponse; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; import io.netty.util.CharsetUtil; /** * 模拟客户端处理器 * @author lh * @date 2015-08-11 14:32 * @version 1.0 * */ public class HttpFileClientHandler extends SimpleChannelInboundHandler<FullHttpResponse> { @Override public void channelActive(ChannelHandlerContext ctx) { String xml = null; try { xml = FileUtils.readFileToString(new File("D:\\workspaces\\eclipse-huifu\\emulator\\xml\\account\\manage\\req.xml")); } catch (IOException e) { e.printStackTrace(); } URI uri = null; try { uri = new URI("http://"+Constants.DEFAULT_IP+":"+Constants.DEFAULT_PORT); } catch (URISyntaxException e) { e.printStackTrace(); } FullHttpRequest req = new DefaultFullHttpRequest(HTTP_1_1, HttpMethod.GET,uri.toASCIIString(), Unpooled.copiedBuffer(xml, CharsetUtil.UTF_8)); req.headers().set(HttpHeaders.Names.HOST, Constants.DEFAULT_IP); req.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); req.headers().set(HttpHeaders.Names.CONTENT_LENGTH, req.content().readableBytes()); ctx.writeAndFlush(req); } @Override public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { cause.printStackTrace(); ctx.close(); } @Override protected void messageReceived(ChannelHandlerContext ctx, FullHttpResponse msg) throws Exception { ByteBuf buf = msg.content(); byte [] resp = new byte[buf.readableBytes()]; buf.readBytes(resp); String xml = new String(resp,"UTF-8"); System.out.println("server cotent:\n"+xml); } }
Constants.java
package emulator; public final class Constants { /** * 电子账户 */ public static final String TC_DZZH = "31001"; /** * 银行卡绑定 */ public static final String TC_YHKBD = "31002"; /** * 客户充值 */ public static final String TC_KHCZ = "31021"; /** * 协议管理 */ public static final String TC_XYGL = "31004"; /** * 项目管理 */ public static final String TC_XMGL = "31005"; /** * 交易成功 */ public static final String TC_JYCG = "0000"; /** * 交易失败 */ public static final String TC_JYSB = "0001"; /** * 部分成功 */ public static final String TC_BFCG = "0002"; /** * 默认IP */ public static final String DEFAULT_IP = "192.168.1.64"; /** * 默认端口 */ public static final int DEFAULT_PORT = 8080; }
相关推荐
NULL 博文链接:https://hbxflihua.iteye.com/blog/2236369
netty的rpc协议的简单实现
Netty实现长连接通讯,连接协议为了简单json封装,如果需要协议变化可以自己封装,有问题可以联系邮箱:lmjlimj@foxmail.com
Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。
Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。
Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。
Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以...Netty的内部实现时很复杂的,但是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的。
Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。
Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...
Dubbo是一个开源的分布式服务框架,旨在帮助开发人员快速而简单...总之,Dubbo协议和Netty框架是实现Dubbo框架的两个关键要素,Dubbo协议实现了分布式应用程序之间的通信,而Netty框架提供了高性能的网络应用程序框架。
Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。
Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...
Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...
“快速和简单”并不意味着应用程序会有难维护和性能低的问题,Netty是一个精心设计的框架,它从许多协议的实现中吸收了很多的经验比如FTP、SMTP、HTTP、许多二进制和基于文本的传统协议,Netty在不降低开发效率、...
Netty的内部实现是很复杂的,但是Netty提供了简单易用的API从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的。 网络应用程序通常需要有较高的可扩展性,无论是Netty还是其他的...
Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...
用Netty实现一个简单的RPC框架,基本上rpc主要的知识点都涉及到了,包括协议的定义,序列化反序列化,动态代理,Spring自动装配,Netty编解码器等。可以通过这个项目加强对Netty的学习掌握,也可以加深对RPC的理解。...
《netty in action中文版》;共有13章; Netty是基于Java NIO的...Netty的内部实现时很复杂的,但是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。 Netty是完全基于NIO实现的,所以整个Netty都是异步的。
Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议。Netty提 供了一种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性。Netty...