package com.ashuo.nettychat.server;
import com.ashuo.nettychat.server.handler.HttpHandler;
import io.netty.bootstrap.ServerBootstrap;
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.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.stream.ChunkedWriteHandler;
public class ChatServer {
private int port = 80;
public void start() {
//boss线程
EventLoopGroup boosGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
//链路配置引擎
ServerBootstrap b = new ServerBootstrap();
//主从模型
b.group(boosGroup, workerGroup).channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG,1024)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
// 子线程业务
//解码和编码 Http请求
ch.pipeline().addLast(new HttpServerCodec());
ch.pipeline().addLast(new HttpObjectAggregator(64*1024));
//用于处理文件流
ch.pipeline().addLast(new ChunkedWriteHandler());
ch.pipeline().addLast(new HttpHandler());
}
});
//阻塞 等待客户连接
ChannelFuture f = b.bind(this.port).sync();
System.out.println("服务已经启动,监听端口是:"+this.port);
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
}finally {
workerGroup.shutdownGracefully();
boosGroup.shutdownGracefully();
}
}
public static void main(String[] args) {
try {
new ChatServer().start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
package com.ashuo.nettychat.server.handler;
import java.io.File;
import java.io.RandomAccessFile;
import java.net.URISyntaxException;
import java.net.URL;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.DefaultFileRegion;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.LastHttpContent;
public class HttpHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
private URL baseURL = HttpHandler.class.getProtectionDomain().getCodeSource().getLocation();
private final String WEB_ROOT = "webroot";
private File GetFileFromRoot(String fileName) throws URISyntaxException {
String path = baseURL.toURI()+WEB_ROOT+"/"+fileName;
path = !path.contains("file:")?path:path.substring(6);
path = path.replaceAll("//", "/");
return new File(path);
}
@Override
//netty 以0结尾的方法都是实现类的方法。Spring 以do 开头的都是实现类的方法
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
// 客户端请求的url
String uri = request.getUri();
String page = uri.equals("/")?"index.html":uri;
RandomAccessFile file =new RandomAccessFile(GetFileFromRoot(page), "r");
String contentType = "text/html;";
//不同的文件返回不懂的头
if(uri.endsWith(".css")) {
contentType = "text/css;";
}else if (uri.endsWith(".js")) {
contentType = "text/javascript;";
}else if(uri.toLowerCase().matches("(jpg|png|gif)$")){
String ext = uri.substring(uri.lastIndexOf("."));
contentType="image/"+ext+";";
}
HttpResponse response = new DefaultHttpResponse(request.getProtocolVersion(), HttpResponseStatus.OK);
response.headers().set(HttpHeaders.Names.CONTENT_TYPE,contentType+"charset=utf-8");
boolean keepAlive = HttpHeaders.isKeepAlive(request);
//长连接处理
if(keepAlive) {
response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,file.length());
response.headers().set(HttpHeaders.Names.CONNECTION,HttpHeaders.Values.KEEP_ALIVE);
}
ctx.write(response);
ctx.write(new DefaultFileRegion(file.getChannel(), 0, file.length()));
//清空缓冲区(不要忘)(不要忘)(不要忘)
ChannelFuture f =ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if(!keepAlive) {
f.addListener(ChannelFutureListener.CLOSE);
}
// System.out.println(file);
}
}
pom
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.ashuo</groupId>
<artifactId>nettychat</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>nettychat</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-all</artifactId>
<version>4.1.6.Final</version>
</dependency>
<dependency>
<groupId>org.msgpack</groupId>
<artifactId>msgpack</artifactId>
<version>0.6.12</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.17</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>