使用netty 作为 http服务器

原创
2010/10/11 17:20
阅读数 4.5W

netty是继mina之后一个非常受欢迎的nio网络框架(其实netty的主程就是mina的主程).

其实netty的介绍就不说了,去看项目介绍吧,直接上代码

httpserver启动和配置类

 

import static org.jboss.netty.channel.Channels.pipeline;

import java.net.InetSocketAddress;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ServerBootstrap;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
import org.jboss.netty.handler.codec.http.HttpChunkAggregator;
import org.jboss.netty.handler.codec.http.HttpRequestDecoder;
import org.jboss.netty.handler.codec.http.HttpResponseEncoder;
import org.jboss.netty.handler.stream.ChunkedWriteHandler;

/**
 * 后台管理服务
 * 
 * @author javagg
 * 
 */
public class AdminServer {
	public static void main(String[] args) {
		start(8080);
	}

	public static void start(int port) {
		// 配置服务器-使用java线程池作为解释线程
		ServerBootstrap bootstrap = new ServerBootstrap(new NioServerSocketChannelFactory(Executors.newCachedThreadPool(), Executors.newCachedThreadPool()));
		// 设置 pipeline factory.
		bootstrap.setPipelineFactory(new ServerPipelineFactory());
		// 绑定端口
		bootstrap.bind(new InetSocketAddress(port));
		System.out.println("admin start on "+port);
	}

	private static class ServerPipelineFactory implements
			ChannelPipelineFactory {
		public ChannelPipeline getPipeline() throws Exception {
			// Create a default pipeline implementation.
			ChannelPipeline pipeline = Channels.pipeline();
			pipeline.addLast("decoder", new HttpRequestDecoder());
			pipeline.addLast("encoder", new HttpResponseEncoder());
			//http处理handler
			pipeline.addLast("handler", new AdminServerHandler());
			return pipeline;
		}
	}
}

 

handler类

import static org.jboss.netty.handler.codec.http.HttpHeaders.Names.CONTENT_TYPE;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.BAD_REQUEST;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.INTERNAL_SERVER_ERROR;
import static org.jboss.netty.handler.codec.http.HttpResponseStatus.OK;
import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;

import java.util.HashMap;

import mmo.test.UITestHandle;

import org.jboss.netty.buffer.ChannelBuffers;
import org.jboss.netty.buffer.DynamicChannelBuffer;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandlerContext;
import org.jboss.netty.channel.ExceptionEvent;
import org.jboss.netty.channel.MessageEvent;
import org.jboss.netty.channel.SimpleChannelUpstreamHandler;
import org.jboss.netty.handler.codec.frame.TooLongFrameException;
import org.jboss.netty.handler.codec.http.DefaultHttpResponse;
import org.jboss.netty.handler.codec.http.HttpRequest;
import org.jboss.netty.handler.codec.http.HttpResponse;
import org.jboss.netty.handler.codec.http.HttpResponseStatus;
import org.jboss.netty.util.CharsetUtil;

/**
 * @author javagg
 */
public class AdminServerHandler extends SimpleChannelUpstreamHandler {

	@Override
	public void messageReceived(ChannelHandlerContext ctx, MessageEvent e)
			throws Exception {
		HttpRequest request = (HttpRequest) e.getMessage();
		String uri = request.getUri();
                          System.out.println("uri:"+uri);
		HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
                          ChannelBuffer buffer=new DynamicChannelBuffer(2048);
		buffer.writeBytes("hello!! 你好".getBytes("UTF-8"));
		response.setContent(buffer);
		response.setHeader("Content-Type", "text/html; charset=UTF-8");
		response.setHeader("Content-Length", response.getContent().writerIndex());
		Channel ch = e.getChannel();
		// Write the initial line and the header.
		ch.write(response);
		ch.disconnect();
		ch.close();
		
	}

	@Override
	public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
			throws Exception {
		Channel ch = e.getChannel();
		Throwable cause = e.getCause();
		if (cause instanceof TooLongFrameException) {
			sendError(ctx, BAD_REQUEST);
			return;
		}

		cause.printStackTrace();
		if (ch.isConnected()) {
			sendError(ctx, INTERNAL_SERVER_ERROR);
		}
	}

	private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
		HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
		response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
		response.setContent(ChannelBuffers.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));

		// Close the connection as soon as the error message is sent.
		ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
	}
}

 

搞定,启动服务器后在ie上输入http://localhost:8080/ 就看到   hello!! 你好

展开阅读全文
打赏
0
19 收藏
分享
加载中
Netty简单应用与线上服务器部署
课程学习地址:http://www.xuetuwuyou.com/course/198
课程出自学途无忧网:http://www.xuetuwuyou.com

一、开发环境
4.1.11.Final
jdk1.8
maven 3.2
Spring 4.3.9


二、适合人群
①想深入学习java ClassLoader
②想在线上linux服务器上运行netty或Springboot服务

三、课程目标
①掌控ClassLoader
②学会编写shell脚本
③了解jvm内存分配
④熟悉线上服务器部署


四、课程目录
1、系统架构技术介绍
2、netty服务器编写
3、netty的编码和解码
4、Netty客户端编写
5、与spring整合
6、netty服务器待解决的问题
7、Classloader类加载器
8、自定义类加载器
9、第二种类加载器
10、热部署
11、类加载器加载外部配置文件
12、项目运行时加载依赖jar
13、项目运行时加载依赖jar第二种方案
14、linux服务器编写通用shell脚本启动JVM
15、优化Shell脚本
16、Shell脚本中加上JVM堆栈内存参数以及垃圾回收机制
17、Netty服务器加上配置信息




Netty课程整合推荐:

Netty简单应用与线上服务器部署
课程观看地址:http://www.xuetuwuyou.com/course/198

深入浅出Netty源码剖析
课程观看地址:http://www.xuetuwuyou.com/course/157

Netty实战高性能分布式RPC
课程观看地址:http://www.xuetuwuyou.com/course/171

NIO+Netty5各种RPC架构实战演练
课程观看地址:http://www.xuetuwuyou.com/course/52

物联网核心技术之Netty入门到精通课程
课程观看地址:http://www.xuetuwuyou.com/course/14

Netty三部曲,夜行侠老师带你玩转netty
课程观看地址:http://www.xuetuwuyou.com/course/175

Netty物联网高并发系统第一季
课程观看地址:http://www.xuetuwuyo
2017/08/16 14:57
回复
举报
那么后续的连接就会从线程池里取(或创建)。那么这和用普通的socket编写网络程序。没有什么优势可言了。。。
==================================================
理解有误!

后续连接不会新创建。
会从workpool中根据负荷均衡原理取出某一个worker线程来绑定。

此外应该避免在worker线程中执行长时间的业务逻辑,如有需要,应该使用带有缓冲池的线程池来执行业务逻辑。
public SocketChannel newChannel(ChannelPipeline pipeline) {
return new NioClientSocketChannel(this, pipeline, sink, workerPool.nextWorker());
}
2015/05/14 14:42
回复
举报

引用来自“铁胆神候”的评论

不知楼主是否测试过传输中文的问题

http://localhost:8080/测试中文传输
URI中的中文解析不出来

使用URLDecoder.decode(uri)解析一下就可以了~
2012/02/12 11:38
回复
举报

引用来自“阿影”的评论

引用来自“guxuede”的评论

引用来自“阿影”的评论

引用来自“zhoutian”的评论

博主你好,我看到你这种是普通HTTP短连接的写法,不知道你能写下长连接情况下的代码吗?我试着写过,但是测试发现1个长连接就需要1个worker线程,有办法不用worker线程来维持长连接吗?

pipeline.addLast("execution", new ExecutionHandler(Executors.newCachedThreadPool()));

Executors.newCachedThreadPool(),是可伸缩的线程池。如果一个连接过来,不close,保持长连接那么他就会占用一个work线程。其他的请求连接会从线程池拿出一个新的线程来work。这样有多少请求就会多少连接。这不是和普通的web服务器一样嘛。
mina一个线程就能hold住很多连接。netty如何设置阿。求指点阿。大哥

pipeline.addLast("execution", new ExecutionHandler(Executors.newCachedThreadPool()));
这句是设置 Handler 使用新线程来执行的,不占用接收TCP/IP的线程。

我现在想避免一个长连接占用一个worker线程(避免线程间切换性能的消耗)。甚至一个线程handle所有连接(当然,不是用于楼主的http服务器)。
mina和cindy都能很好的配置acceptor thread和processor thread在单线程下或线程池下工作。
但是netty一个连接不关闭的话,就会蛋疼的阻塞了。那么后续的连接就会从线程池里取(或创建)。那么这和用普通的socket编写网络程序。没有什么优势可言了。。。
2011/11/27 17:41
回复
举报

引用来自“guxuede”的评论

引用来自“阿影”的评论

引用来自“zhoutian”的评论

博主你好,我看到你这种是普通HTTP短连接的写法,不知道你能写下长连接情况下的代码吗?我试着写过,但是测试发现1个长连接就需要1个worker线程,有办法不用worker线程来维持长连接吗?

pipeline.addLast("execution", new ExecutionHandler(Executors.newCachedThreadPool()));

Executors.newCachedThreadPool(),是可伸缩的线程池。如果一个连接过来,不close,保持长连接那么他就会占用一个work线程。其他的请求连接会从线程池拿出一个新的线程来work。这样有多少请求就会多少连接。这不是和普通的web服务器一样嘛。
mina一个线程就能hold住很多连接。netty如何设置阿。求指点阿。大哥

pipeline.addLast("execution", new ExecutionHandler(Executors.newCachedThreadPool()));
这句是设置 Handler 使用新线程来执行的,不占用接收TCP/IP的线程。
2011/11/25 20:39
回复
举报

引用来自“阿影”的评论

引用来自“zhoutian”的评论

博主你好,我看到你这种是普通HTTP短连接的写法,不知道你能写下长连接情况下的代码吗?我试着写过,但是测试发现1个长连接就需要1个worker线程,有办法不用worker线程来维持长连接吗?

pipeline.addLast("execution", new ExecutionHandler(Executors.newCachedThreadPool()));

Executors.newCachedThreadPool(),是可伸缩的线程池。如果一个连接过来,不close,保持长连接那么他就会占用一个work线程。其他的请求连接会从线程池拿出一个新的线程来work。这样有多少请求就会多少连接。这不是和普通的web服务器一样嘛。
mina一个线程就能hold住很多连接。netty如何设置阿。求指点阿。大哥
2011/11/25 10:01
回复
举报

引用来自“zhoutian”的评论

博主你好,我看到你这种是普通HTTP短连接的写法,不知道你能写下长连接情况下的代码吗?我试着写过,但是测试发现1个长连接就需要1个worker线程,有办法不用worker线程来维持长连接吗?

pipeline.addLast("execution", new ExecutionHandler(Executors.newCachedThreadPool()));
2011/08/16 11:44
回复
举报
请教个问题:我的jdk版本是1.6.0.23 ,运行平台MyEclipse8.5,为啥就导入不了org.jboss.netty包呢?
2011/06/25 17:55
回复
举报
博主你好,我看到你这种是普通HTTP短连接的写法,不知道你能写下长连接情况下的代码吗?我试着写过,但是测试发现1个长连接就需要1个worker线程,有办法不用worker线程来维持长连接吗?
2011/06/10 14:30
回复
举报
不知楼主是否测试过传输中文的问题

http://localhost:8080/测试中文传输
URI中的中文解析不出来
2011/04/26 15:51
回复
举报
更多评论
打赏
10 评论
19 收藏
0
分享
返回顶部
顶部