使用Netty进行文件传输

释放双眼,带上耳机,听听看~!

一、简介

使用Netty进行文件传输主要涉及到FileChannel文件通道,它用来连接文件,可以通过这个通道读写文件。在使用FileChannel之前必须先打开它,FileChannel无法直接打开,可以通过InputStream、OutputStream或RandomAccessFile来获取FileChannel实例,比如:


1
2
3
4
1RandomAccessFile file=new RandomAccessFile("D:\test.txt","rw");
2FileChannel channel=file.getChannel();
3
4

如果需要从FileChannel中读取数据,要申请一个ByteBuffer,将数据从FileChannel读取到缓冲区中。read()方法返回的int值表示有多少个字节被读取到了缓冲区中,如果返回-1,表示读取到了文件末尾。

如果需要通过FileChannel向文件中写入数据,需要将数据复制或直接写入到ByteBuffer中,然后调用FileChannel.write()方法进行写操作,比如:


1
2
3
4
5
6
7
1String content="test filechannel";
2ByteBuffer writeBuffer=ByteBuffer.allocate(1024);
3writeBuffer.put(content.getBytes());
4writeBuffer.flip();
5channel.write(buf);
6
7

使用完FileChannel之后需要通过close()方法关闭文件句柄,否则可能出现句柄泄漏。

可以通过FileChannel的position(long pos)方法设置文件的位置指针,通过这种方式可以实现文件的随机读写。

二、Netty文件传输服务端

实现步骤如下:

1)Netty文件服务器启动,绑定8888作为内部监听端口;

2)在命令提示符窗口,通过telnet和文件服务器建立TCP连接;

3)在控制台输入需要下载的文件的绝对路径;

4)文件服务器接收到请求后进行合法性判断,如果文件存在,就将文件发送给控制台;

5)控制台打印文件名和文件内容。

下面是服务端实现:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
1import io.netty.bootstrap.ServerBootstrap;
2import io.netty.channel.ChannelFuture;
3import io.netty.channel.ChannelInitializer;
4import io.netty.channel.ChannelOption;
5import io.netty.channel.EventLoopGroup;
6import io.netty.channel.nio.NioEventLoopGroup;
7import io.netty.channel.socket.SocketChannel;
8import io.netty.channel.socket.nio.NioServerSocketChannel;
9import io.netty.handler.codec.LineBasedFrameDecoder;
10import io.netty.handler.codec.string.StringDecoder;
11import io.netty.handler.codec.string.StringEncoder;
12import io.netty.handler.logging.LogLevel;
13import io.netty.handler.logging.LoggingHandler;
14import io.netty.util.CharsetUtil;
15
16public class FileServer
17{
18    public void run (int port)throws Exception{
19        EventLoopGroup bossGroup=new NioEventLoopGroup();
20        EventLoopGroup workerGroup=new NioEventLoopGroup();
21        try
22        {
23            ServerBootstrap b=new ServerBootstrap();
24            b.group(bossGroup,workerGroup)
25            .channel(NioServerSocketChannel.class)
26            .option(ChannelOption.SO_BACKLOG, 100)
27            .handler(new LoggingHandler(LogLevel.INFO))
28            .childHandler(new ChannelInitializer<SocketChannel>()
29            {
30
31                @Override
32                protected void initChannel(SocketChannel ch)
33                    throws Exception
34                {
35                    ch.pipeline().addLast(new StringEncoder(CharsetUtil.UTF_8),
36                                          //按照回车换行符对数据包进行解码
37                                          new LineBasedFrameDecoder(1024),
38                                          new StringDecoder(CharsetUtil.UTF_8),
39                                          new FileServerHandler());
40                }
41            });
42            ChannelFuture f=b.bind(port).sync();
43            System.out.println("Start file server at port : "+port);
44            f.channel().closeFuture().sync();
45        }
46        catch (Exception e)
47        {
48            e.printStackTrace();
49        }
50        finally{
51            bossGroup.shutdownGracefully();
52            workerGroup.shutdownGracefully();
53        }
54    }
55    
56    public static void main(String[] args)throws Exception
57    {
58        int port =8888;
59        try
60        {
61            if (args!=null&&args.length>0)
62            {
63                port=Integer.valueOf(args[0]);
64            }
65        }
66        catch (Exception e)
67        {
68            e.printStackTrace();
69        }
70        new FileServer().run(port);
71    }
72}
73
74

下面是网络
IO
事件的处理:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
1import java.io.File;
2import java.io.RandomAccessFile;
3
4import io.netty.channel.ChannelHandlerContext;
5import io.netty.channel.DefaultFileRegion;
6import io.netty.channel.FileRegion;
7import io.netty.channel.SimpleChannelInboundHandler;
8
9public class FileServerHandler extends SimpleChannelInboundHandler<String>
10{
11    //操作系统识别的换行符
12    private static final String CR=System.getProperty("line.separator");
13    
14    @Override
15    protected void messageReceived(ChannelHandlerContext ctx, String msg)
16        throws Exception
17    {
18        File file=new File(msg);
19        if (file.exists())
20        {
21            if (!file.isFile())
22            {
23                //写入换行符表示文件结束
24                ctx.writeAndFlush("Not a file: "+file+CR);
25                return;
26            }
27            //换行符表示文件结尾
28            ctx.write(file+" "+file.length()+CR);
29            RandomAccessFile randomAccessFile=new RandomAccessFile(msg, "r");
30            FileRegion region=new DefaultFileRegion(
31                randomAccessFile.getChannel(), 0, randomAccessFile.length());
32            ctx.write(region);
33            //写入换行符表示文件结束
34            ctx.writeAndFlush(CR);
35            randomAccessFile.close();
36        }else {
37            ctx.writeAndFlush("File not found: "+file+CR);
38        }
39    }
40    
41    @Override
42    public void exceptionCaught(ChannelHandlerContext ctx,Throwable cause){
43        cause.printStackTrace();
44        ctx.close();
45    }
46}
47
48

三、测试

启动文件服务器服务端后,打开命令提示符窗口,输入
telnet localhost 8888
和文件服务器建立
TCP
连接,然后输入一个文件路径进行验证:

使用Netty进行文件传输

使用Netty进行文件传输

使用Netty进行文件传输

参考书籍《Netty权威指南》

给TA打赏
共{{data.count}}人
人已打赏
安全技术

详解Node.js API系列 Http模块(2) CNodejs爬虫实现

2021-12-21 16:36:11

安全技术

从零搭建自己的SpringBoot后台框架(二十三)

2022-1-12 12:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索