一、前言
Netty 是一个可以快速开发网络应用程序的 NIO 框架,它大大简化了 TCP 或者 UDP 服务器的网络编程。Netty 的简易和快速开发并不意味着由它开发的程序将失去可维护性或者存在性能问题,它的设计参考了许多协议的实现,比如 FTP、SMTP、HTTP 和各种二进制和基于文本的传统协议,因此 Netty 成功的实现了兼顾快速开发,性能,稳定性,灵活性为一体,不需要为了考虑一方面原因而妥协其他方面。Netty 的应用还是比较广泛的,比如阿里巴巴开源的 Dubbo 和 Sofa-Bolt 框架底层网络通讯都是基于 Netty 来实现的。
本 Chat 我们来使用 Netty 搭建一个文件上传服务,主要包含下面内容:
使用 Netty 搭建文件上传服务端,自定义协议格式,自定义解码处理器,允许一个长连接连续上传多个文件。
使用 Netty 搭建文件上传客户端,从本地读取文件,按照自定义协议格式通过 Netty 连接传输文件到服务器端 。
二、文件上传服务设计
我们知道通过网络传输数据时候只是传递二进制流,比如客户端通过网络 socket 给服务器端发送数据时候,客户端把要发送的数据对象序列化为二进制后,通过 socket 连接直接发送给了服务器,服务器则要负责解决半包和粘包问题(参考:Java NIO 框架 Netty 之美:粘包与半包问题),同理客户端上传一个文件时候,也是把磁盘文件转换为了二进制流通过 socket 连接发送给文件服务器,那么服务器端则也要解决半包和粘包问题,也就是服务器要能知道一个文件的边界(读取到那个字节时候才是一个完整的文件),常用的解决半包粘包的问题有三种:包定长、分隔符、自定义帧(header+body),本文简单的使用 header+body 的变体,如下图方式来解决文件边界问题:
如上图协议首先是 4 个字节用来记录文件的长度,然后使用 128 字节用来存放文件名称,然后接下来的 fileLength 个字节是文件的具体内容。另外本文搭建的简单文件上传服务器支持同一个链接传递多个文件,这时候字节流的格式就如下图两个文件在网络流传输时候的示意图:
到这里位置我们设计了一个简单的包协议,客户端上传在链接建立完毕后只需要先向 socket 写入一个 4 字节的 int 类型的数据来代表要上传文件的大小,然后传递 128 字节的字符串来代表文件的名字,最后从磁盘读取文件流并依次写入到 socket 就可以了。如果要上传多个文件则重复上述过程。