netty实现文件服务器的一些功能

服务器代码:

package com.caohao.jiami.learn1.nettytest;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.epoll.EpollServerSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.logging.LoggingHandler;
import io.netty.handler.timeout.IdleState;
import io.netty.handler.timeout.IdleStateEvent;
import io.netty.handler.timeout.IdleStateHandler;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.util.Date;
import java.util.List;
import java.util.Timer;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 简单的文件服务器
 *  要实现的功能
 *      1。将文件上传到文件服务器
 *      2。将文件服务器中的文件下载到本地
 *      3。查看文件服务器上的文件树形存储结构
 *
 */
public class test3 {
    public static String BASEPATH = "/Users/caohao/IdeaProjects/myftptest/";
    private EventLoopGroup parentGroup = new NioEventLoopGroup();
    private EventLoopGroup childGroup = new NioEventLoopGroup();
    private ServerBootstrap bootstrap;
    private ChannelFuture future;
    public void start(int port){
        try {
            bootstrap = new ServerBootstrap();
            bootstrap.group(parentGroup,childGroup);
            bootstrap.handler(new LoggingHandler());
            bootstrap.childHandler(new channeliniternized());
            bootstrap.channel(NioServerSocketChannel.class);
            future= bootstrap.bind(port).sync();
            future.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            System.err.println("启动失败");
        } finally {
            parentGroup.shutdownGracefully();
            childGroup.shutdownGracefully();
        }
    }

    public static void main(String[] args) {
        test3 test3 = new test3();
        test3.start(9010);
    }

}

/**
 * inboundhandler:
 *      1.解决沾包问题,通过在消息头加入文件字节流长度的int值,每次先读取4个字节来判断文件长度
 *      2。接受byte流将其传入fileoutputstream并存入本地
 */
class channeliniternized extends ChannelInitializer<SocketChannel>{

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new IdleStateHandler(10,10,0, TimeUnit.SECONDS));
        pipeline.addLast(new test3bytetobytedecoder());
        pipeline.addLast(new test3handler());
    }
}
class test3bytetobytedecoder extends ByteToMessageDecoder{

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        in.markReaderIndex();
        int i = in.readInt();
        System.out.println("our request is "+i);
        if (i==0){//请求下载文件
            in.markReaderIndex();
            int filenamelength = in.readInt();
            byte[] bytes = new byte[filenamelength];
            System.out.println("request files name length is "+filenamelength);
            if (in.readableBytes()>=filenamelength){
                in.readBytes(bytes);
                String filename = new String(bytes);
                System.out.println("target file name is "+filename);
                FileInputStream inputStream = new FileInputStream(test3.BASEPATH+filename);
                ByteBuf buffer = Unpooled.buffer();
                int c;
                while ((c = inputStream.read())!=-1){
                    buffer.writeInt(c);
                }
                int readableBytes = buffer.readableBytes();
                byte[] file = new byte[readableBytes];
                System.out.println("out tranfor file length is "+readableBytes);
                buffer.readBytes(file);
                ctx.channel().write(readableBytes);
                ctx.channel().writeAndFlush(file);
                out.add("filedownload".getBytes());
            }else {
                bytes = null;
                in.resetReaderIndex();
            }
        }else {//请求文件上传
            System.out.println("储存为文件头中的长度信息为"+i);
            byte[] bytes = new byte[i];
            if (in.readableBytes()>=i){
                in.readBytes(bytes);
                out.add(bytes);
            }else {
                bytes = null;
                in.resetReaderIndex();
            }
        }

    }
}
class test3handler extends SimpleChannelInboundHandler<byte[]>{
    private int count = 0;

    @Override
    public void channelRegistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("一个文件连接到FTP服务器");
    }

    @Override
    public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
        if (evt instanceof IdleStateEvent){
            IdleStateEvent event = (IdleStateEvent) evt;
            if (IdleState.READER_IDLE.equals(event.state())){
                if (count >= 3){
                    ctx.channel().close();
                }else {
                    System.err.println("一次连接超时");
                    count+=1;
                }
            }
        }
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, byte[] msg) throws Exception {
        if (new String(msg).equals("filedownload")){
            System.out.println("filedownload");
        }else {
            String filename = null;
            filename = UUID.randomUUID().toString()+ new Date().toString();
            System.out.println("新加入的文件名字设定为"+filename+".ico");
            ctx.channel().writeAndFlush("新加入的文件名字设定为"+filename+".ico");
            FileOutputStream outputStream = new FileOutputStream(test3.BASEPATH+filename+".ico");
            System.out.println("file length is "+msg.length);
            outputStream.write(msg);
            outputStream.flush();
            outputStream.close();
        }

    }

    @Override
    public void channelUnregistered(ChannelHandlerContext ctx) throws Exception {
        System.out.println("一个连接离开FTP服务器");
    }

    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.err.println("文件传输过程中发生错误,中断传输");
        ctx.channel().close();
    }
}


连接服务器的API代码:

package com.caohao.jiami.learn1.nettytest;

import io.netty.bootstrap.Bootstrap;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.*;
import io.netty.channel.epoll.EpollSocketChannel;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.List;

public class test3connecttool {
    NioEventLoopGroup group = new NioEventLoopGroup(1);
    ChannelFuture connect = null;
    public void connect(){
        try {
            Bootstrap bootstrap = new Bootstrap();
            connect = bootstrap.group(group).channel(NioSocketChannel.class).handler(new test3clintinitelaizer()).connect("127.0.0.1", 9010).sync();
        } catch (Exception e) {
            System.err.println("连接失败");
            group.shutdownGracefully();
        }

    }
    public void stop(){
        try {
            connect.channel().closeFuture().sync();
        } catch (InterruptedException e) {
            System.out.println("err");
        }finally {
            group.shutdownGracefully();
        }

    }
    public static void main(String[] args) {
        test3connecttool test3connecttool = new test3connecttool();
        test3connecttool.connect();
//        test3connecttool.sendmessage("/Users/caohao/test/httpserver/favicon.ico");测试通过
        test3connecttool.downloadmessage("4fe9cff2-a4f2-4285-86a3-7ff03ed2e589Fri May 29 13:33:20 CST 2020.ico");
        test3connecttool.stop();
    }
    public void sendmessage(String filepath){
        ByteBuf buffer = Unpooled.buffer();
        byte[] filepathBytes = filepath.getBytes();
        buffer.writeInt(1);
        buffer.writeBytes(filepathBytes);
        connect.channel().writeAndFlush(buffer);
    }
    public void downloadmessage(String filename){
        ByteBuf buffer = Unpooled.buffer();
        byte[] filepathBytes = filename.getBytes();
        buffer.writeInt(2);
        buffer.writeBytes(filepathBytes);
        connect.channel().writeAndFlush(buffer);
    }
}
class test3clintinitelaizer extends ChannelInitializer<SocketChannel> {

    @Override
    protected void initChannel(SocketChannel ch) throws Exception {
        ChannelPipeline pipeline = ch.pipeline();
        pipeline.addLast(new test3bytetobytedecoder());
        pipeline.addLast(new test3inboundhandler());
        pipeline.addLast(new test3clienthandler());
    }
}
class test3clienthandler extends MessageToByteEncoder<ByteBuf>{


    @Override
    protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) throws Exception {
        //读取一个int如果是1 就是文件上传,如果是2就是文件下载
        if (msg.readInt()==1) {
            FileInputStream inputStream = null;
            try {
                int l = msg.readableBytes();
                byte[] message = new byte[l];
                msg.readBytes(message);
                String s = new String(message);
                System.out.println("our target file is "+s);
                inputStream = new FileInputStream(s);
                ByteBuf byteBuf = Unpooled.buffer();
                int c ;
                while ((c=inputStream.read())!=-1){
                    byteBuf.writeByte(c);
                }
                int len = byteBuf.readableBytes();
                byte[] body = new byte[len];
                byteBuf.readBytes(body);
                System.out.println("file length is "+len);
                out.writeInt(len);
                out.writeBytes(body);
            } catch (IOException e) {
                System.err.println("文件读取失败");
            } finally {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    System.err.println("文件流关闭失败");
                }
            }
        } else {
            out.writeInt(0);//0代表文件下载
            int l = msg.readableBytes();
            byte[] filename = new byte[l];
            msg.readBytes(filename);
            String s = new String(filename);
            System.out.println("我们请求下载文件"+s);
            out.writeInt(filename.length);
            out.writeBytes(filename);
        }

    }
}
class test3clientbytetomessagedecoder extends ByteToMessageDecoder{

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        in.markReaderIndex();
        int len = in.readInt();
        System.out.println("our reponse file length is "+len);
        if (in.readableBytes()>=len){
            byte[] body = new byte[len];
            in.readBytes(body);
            FileOutputStream outputStream = null;
            try {
                outputStream = new FileOutputStream("/Users/caohao/IdeaProjects/myftptest/testico.ico");
                outputStream.write(body);
                out.add("file download success");
            } catch (IOException e) {
                e.printStackTrace();
                System.err.println("file download failed");
                out.add("file download failed");
            } finally {
                outputStream.close();
            }
        }else {
            in.resetReaderIndex();
        }

    }
}
class test3inboundhandler extends SimpleChannelInboundHandler<String>{

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception {
        System.out.println(msg);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值