`
hbxflihua
  • 浏览: 658531 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

Netty HTTP协议简单实现

阅读更多

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;	

}

 

分享到:
评论

相关推荐

    Netty TCP协议简单实现

    NULL 博文链接:https://hbxflihua.iteye.com/blog/2236369

    netty的rpc协议的简单实现

    netty的rpc协议的简单实现

    Netty实现长连接通讯-连接协议为了简单json封装

    Netty实现长连接通讯,连接协议为了简单json封装,如果需要协议变化可以自己封装,有问题可以联系邮箱:lmjlimj@foxmail.com

    Netty (netty-netty-4.0.56.Final.tar.gz)

    Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

    netty-netty-3.10.6.Final.tar.gz

    Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

    Netty (netty-netty-5.0.0.Alpha2.tar.gz)

    Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

    Netty_In_Action中文版

    Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以...Netty的内部实现时很复杂的,但是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的。

    Netty (netty-netty-4.1.74.Final.tar.gz)

    Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

    netty-demo实例

    Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...

    dubbo协议、netty框架总结

    Dubbo是一个开源的分布式服务框架,旨在帮助开发人员快速而简单...总之,Dubbo协议和Netty框架是实现Dubbo框架的两个关键要素,Dubbo协议实现了分布式应用程序之间的通信,而Netty框架提供了高性能的网络应用程序框架。

    Netty (netty-netty-4.1.77.Final.tar.gz)

    Netty 是根据从实现许多协议(如 FTP、SMTP、HTTP 以及各种二进制和基于文本的旧协议)中获得的经验精心设计的。因此,Netty 成功地找到了一种方法,可以在不妥协的情况下实现易于开发、性能、稳定性和灵活性。

    netty电子书

    Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...

    netty4官方包

    Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...

    Netty5学习指南

    “快速和简单”并不意味着应用程序会有难维护和性能低的问题,Netty是一个精心设计的框架,它从许多协议的实现中吸收了很多的经验比如FTP、SMTP、HTTP、许多二进制和基于文本的传统协议,Netty在不降低开发效率、...

    Netty权威指南

    Netty的内部实现是很复杂的,但是Netty提供了简单易用的API从网络处理代码中解耦业务逻辑。Netty是完全基于NIO实现的,所以整个Netty都是异步的。 网络应用程序通常需要有较高的可扩展性,无论是Netty还是其他的...

    netty-demo

    Netty 是一个吸收了多种协议的实现经验,这些协议包括FTP,SMTP,HTTP,各种二进制,文本协议,并经过相当精心设计的项目,最终,Netty 成功的找到了一种方式,在保证易于开发的同时还保证了其应用的性能,稳定性和...

    用Netty实现一个简单的RPC框架

    用Netty实现一个简单的RPC框架,基本上rpc主要的知识点都涉及到了,包括协议的定义,序列化反序列化,动态代理,Spring自动装配,Netty编解码器等。可以通过这个项目加强对Netty的学习掌握,也可以加深对RPC的理解。...

    《netty in action中文版》13章全

    《netty in action中文版》;共有13章; Netty是基于Java NIO的...Netty的内部实现时很复杂的,但是Netty提供了简单易用的api从网络处理代码中解耦业务逻辑。 Netty是完全基于NIO实现的,所以整个Netty都是异步的。

    Netty In Action中文版

    Netty是一个NIO client-server(客户端服务器)框架,使用Netty可以快速开发网络应用,例如服务器和客户端协议。Netty提 供了一种新的方式来使开发网络应用程序,这种新的方式使得它很容易使用和有很强的扩展性。Netty...

Global site tag (gtag.js) - Google Analytics