使用Netty实现一个简单的FTP服务器
引入Netty的依赖
<dependency>
<groupId>io.netty</groupId>
<artifactId>netty-codec-http</artifactId>
<version>4.1.45.Final</version>
</dependency>
服务端:
/**
* @Author Joker
* @Date 2020/11/15
* @since 1.8
*/
public class HttpServerDemo {
public static void main(String[] args) throws Exception {
// 创建两个线程池
NioEventLoopGroup acceptEventExecutors = new NioEventLoopGroup();
NioEventLoopGroup readEventExecutors = new NioEventLoopGroup();
// 1、创建ServerBootstrap
ServerBootstrap serverBootstrap = new ServerBootstrap();
// 2.配置ServerBootstrap
ChannelFuture channelFuture = serverBootstrap
// 设置netty线程模型
.group(acceptEventExecutors, readEventExecutors)
// 设置Netty、类型
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer() {
@Override
protected void initChannel(Channel channel) throws Exception {
// 链式
ChannelPipeline pipeline = channel.pipeline();
// 添加入栈的处理器 ---》把ByteBuf转成字符串
pipeline.addLast(new HttpServerCodec());
// 添加入栈处理器 --》把字符串转成HttpFullRequest对象
pipeline.addLast(new HttpObjectAggregator(1024));
pipeline.addLast(new HttpServletRequest());
}
})
// 绑定端口的操作是异步的
.bind(8888);
// 阻塞
channelFuture.sync();
System.out.println("HTTP服务端启动成功。。。");
}
}
请求处理器(这里相比较前面代码多了一些):
/**
* @Author Joker
* @Date 2020/11/15
* @since 1.8
*/
public class HttpServletRequest extends SimpleChannelInboundHandler<FullHttpRequest> {
final String GET_REQUEST = "GET";
// 文件夹路劲自己设一个就行 我这里乱写了一个我maven仓库地址
final String FILE_PATH = "D:" + File.separator + "Maven-Repository";
final String CONTEXT_TYPE = "Context-type";
final String HTML_TYPE = "text/html;charset=UTF-8";
final String CONTENT_LENGTH = "Content-Length";
@Override
protected void channelRead0(ChannelHandlerContext channelHandlerContext, FullHttpRequest request) throws Exception {
// 获取用户的uri
String uri = request.uri();
String name = request.method().name();
// 只支持GEt请求
if (!GET_REQUEST.equals(name)) {
// 响应浏览器
responseError("只支持GET请求", channelHandlerContext);
return;
}
File file = new File(FILE_PATH + URLDecoder.decode(uri, "UTF-8"));
if (!file.exists()) {
responseError("文件不存在。。。", channelHandlerContext);
return;
}
if (file.isFile()) {
// 如果是一个文件,就执行下载
responseFileCopy(file, channelHandlerContext);
} else {
// 如果是一个目录就显示子目录
responseDir(channelHandlerContext, file, uri);
}
}
/**
* 文件下载
* @param file
* @param channelHandlerContext
*/
private void responseFileCopy(File file, ChannelHandlerContext channelHandlerContext) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.headers().add(CONTEXT_TYPE, "application/octet-stream");
response.headers().add(CONTENT_LENGTH, file.length());
Channel channel = channelHandlerContext.channel();
FileInputStream ips = null;
try {
ips = new FileInputStream(file);
byte[] by = new byte[1024];
int read = -1;
while ((read = ips.read(by, 0, by.length)) != -1) {
response.content().writeBytes(by, 0, read);
}
channel.writeAndFlush(response);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (ips != null) {
try {
ips.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
/**
* 响应目录信息
* @param channelHandlerContext
* @param file
* @param uri
*/
private void responseDir(ChannelHandlerContext channelHandlerContext, File file, String uri) {
StringBuffer buffer = new StringBuffer();
// 获取目录的子文件
File[] files = file.listFiles();
for (File file1 : files) {
if ("/".equals(uri)) {
buffer.append("<li><a href= '" + uri + file1.getName() + "'>" + file1.getName() + "</a></li>");
} else {
buffer.append("<li><a href= '" + uri + File.separator + file1.getName() + "'>" + file1.getName() + "</a></li>");
}
}
responseClient(buffer.toString(), channelHandlerContext);
}
/**
* 响应客户端
* @param text
* @param channelHandlerContext
*/
public void responseClient(String text, ChannelHandlerContext channelHandlerContext) {
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
// 设置响应头
response.headers().add(CONTEXT_TYPE, HTML_TYPE);
String msg = "<html> \t<meta charset=\"UTF-8\" />" + text + "</html>";
try {
response.content().writeBytes(msg.getBytes("UTF-8"));
channelHandlerContext.channel().writeAndFlush(response);
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
}
/**
* 响应错误信息
* @param text
* @param channelHandlerContext
*/
public void responseError(String text, ChannelHandlerContext channelHandlerContext) {
String msg = "<h1>" + text + "</h1>";
responseClient(msg, channelHandlerContext);
}
}