实验目的
- 应用层文件传输的原理
- 传输层协议选用
用户通过一个FTP用户代理和FTP交互。用户提供远程主机的主机名,本地的FTP客户进程建立一个到远程主机FTP服务器进程的TCP连接。用户提供用户标识和口令,作为FTP命令的一部分在该TCP连接上传送。服务器向用户授权,用户可以将存放在本地文件系统中的多个文件复制到远程文件系统。HTTP和FTP都是建立在TCP上的应用层文件传输协议。FTP的控制信息是带外传送的。HTTP是带内发送控制信息的。
FTP使用了两个并行的TCP连接来传输文件:
1.控制连接:用于在两主机之间传输控制消息,如用户标识、口令、改变远程目录的命令以及存放/获取文件的命令
2.数据连接:用于实际发送一个文件
用户主机与远程主机开启一个FTP会话时:
1.FTP的客户端在服务器21号端口与服务器端发起一个用于控制的TCP连接
2.FTP的客户端通过控制连接发送用户的表示和口令,发送改变远程目录的命令
3.当FTP的服务器端从该连接上收到一个文件传输的命令后,就发起一个到客户端的TCP数据连接
4.FTP在数据连接上传送一个文件,然后关闭该连接
注意:
1.在同一个会话期间,如果用户还需要传输另外一个文件,FTP打开另一个数据连接
2.对于控制连接,贯穿于整个会话期间
3.FTP服务器必须在整个会话期间保留用户的状态,是有状态的
FTP命令和回答:
以7比特ASCII格式在控制连接上传送。每个命令由4个大写字母ASCII字符组成
User username:向服务器传送用户标识
PASS password:向服务器传送用户口令
LIST:用于请求服务器会送当前远程目录中的所有文件列表,文件列表在新建的数据连接上传送
RETR filename:用于从远程主机当前目录检索文件,该命令引起远程主机发起一个数据连接,并经该数据连接发送所请求的文件
STOR filename:用于在远程主机的当前目录上存放文件
典型的回答:
331 Username OK , Password required
125 Data connection already open; transfer starting
425 Cam’t open data connection
452 Error writing file
- 应用层协议设计
为了让数据能够按时间序列存储以及按时间序列设计索引取出数据,并且能够在应用层对数据包进行校验,能够用过状态机编程以实现数据的检验,重传,成功发送等多种状态。
具体设计如下:
时间戳字段,字段名time_stamp, 数据格式 time_t, 由七个uint16_t构成的结构体,
分别表示年-月-日-时-分-秒-毫秒。时间戳字段一方面用于作为数据传输的校验功能,另一方面用于数据的存储与按时间回放,将时间戳作为key构建索引。
1秒几帧图像字段,字段名fps, 数据格式uint16_t,表示一秒由几帧图像,用于在 应用层将图像数据的拼接。
帧数字段,字段名frame,数据格式uint16_t, 表示当前图像数据属于第几帧,和 fps字段配合使用。按序将数据包拼接。
设备通道号字段,字段名channel,数据格式uint16_t,由于数据是多源传感器来的,因此可能出现同一时刻不同设备的数据需要存储,因此需要加设备通道号字段
图像包序号字段,字段名index,数据格式uint16_t, 标记当前数据包的序号,为了检验接收端是否完整接收数据包
数据包大小字段,字段名size,数据格式uint32_t, 标记当前数据包实际发送了多少字节的数据,为了接收端校验是否完整接收数据包
设计了4个标志位,结合状态机编程以实现应用层的校验,重传,确认机制,由于状态位用0, 1即可表示,因此设计成位图(bitmap)存储,可以节省32倍空间
确认号标志位,字段名ACK, 数据格式bitmap,数据包是否接收标志位,如果已经接收则字段值设为1,如果没有则设为0
//使用状态机例子,利用位运算实现状态转换:
#define ACK 0x01
#define NOACK 0x00
Package package;//收到的数据包
if (数据包传输成功) {
package.ack |= ACK;
} else {
package.ack |= NOACK;
}
if (package.ack & ACK) {
//成功传输后续处理
} else if (package.ack & ACKNO) {
//传输失败,丢弃数据 or 重传数据包
}
重传标志位,字段名RST, 数据格式bitmap,数据包如果接收端经校验之后丢包,则开启重传标志, 发送端开始重传数据包代码,需要重传则设为1, 否则设为0
例子可参考ACK
检验位,字段名CHECK, 数据格式bitmap,接收端完成对数据包大小和序号的校验之后,如果正确则将校验位置为1,代表校验成功,否则代表校验失败,需要 经过重传处理
例子可参考ACK
完成标志位,字段名FINISH,数据格式bitmap,接收端经校验后收到完整的数据包,则完成标志位的值置为1,表示当前数据包完成发送,可开启下个数据包的发送,否则一直值为0,发送端与接收端继续保持当前数据包的传输
例子可参考ACK
保留标志位,字段名OFFSET,可扩充字段,当程序需要加入新的状态的时候可以直接增加标志位,而不用改变之前的数据结构的内存布局,同时作为偏移量补充之前状态位。
原始数据,字段rawdata,数据类型位uint16_t[],大小控制在1000字节/包以内,考虑到底层传输效率与拆包丢包,数据包所有字节加一起应小于链路层的最小传输单元(1500字节),去除网络层的ip包头(20字节,用于寻址),传输层的tcp包头(20字节,用于可靠传输)/udp包头(8字节,基本多路复用/多路分解),应用层包头(31字节),因此一个包的数据应控制在1000字节。
//数据包设计
//日期
typedef struct Date {
bool use_string;
uint16_t year;
uint16_t month;
uint16_t day;
uint16_t hour;
uint16_t minute;
uint16_t second;
string time; // YYYY-MM-DD h-m-s
} Date_t;
//通道
typedef enum Channel {
A = 1,
B = 2,
C = 3,
D = 4
} Channel_t;
//1秒6帧图像
typedef enum Frame {
ONE = 1,
TWO = 2,
THREE = 3,
FOUR = 4,
FIVE = 5,
SIX = 6
} Frame_t;
typedef struct PackageHead {
Date_t time_stamp; //时间戳
uint16_t fps;//1秒几帧图像
Frame_t frame; //帧数
Channel_t channel; //通道编号
uint8_t index; //图像包序号,一帧图像会拆包,底层有最大传输单元限制,一个包最多有1500字节 - TCP/UDP包头 - 应用层协议包头
uint16_t data_size; //传输的数据包大小
bool reliable; //可靠传输标志位
bool ack; //确认号标志位
bool rst; //重传标志位
uint16_t seq; //udp包序号
bool finish; //一帧图像是否传完
uint8_t offset[16]; //16字节可扩容字段
} PackageHead;
typedef struct Package {
PackageHead head; //包头
uint8_t raw_data[1000]; //最好不要超过1000字节
} Package;
//位图设计
class Bitmap {
public:
Bitmap(int size, int _key = 32)
{
key = _key;
buffer.resize(size / key + 1);
}
void insert(int value)
{
int seg_index = value / key;
int index = value % key;
buffer[seg_index] |= (1 << index);
}
void get(int value)
{
int seg_index = value / key;
int index = value % key;
if (buffer[seg_index] & (1 << index)) {
cout << value << " is in bitmap" << endl;
} else {
cout << value << "is not int bitmap" << endl;
}
}
private:
vector<uint32_t> buffer;
int key;
};
//状态机编程
#define ACK 0x01
#define NOACK 0x00
Package package;//收到的数据包
if (数据包传输成功) {
package.ack |= ACK;
} else {
package.ack |= NOACK;
}
if (package.ack & ACK) {
//成功传输后续处理
} else if (package.ack & ACKNO) {
//传输失败,丢弃数据 or 重传数据包
}
- 误码
需求
编写发送软件和接收软件,将指定文件夹的文件发送到另一个文件夹:
1.支持Windows和Linux路径名(服务器端和客户端不在同一平台)
2.文件夹下所有子文件夹也即时传输
3.误码文件不输出,重传失败后记录并告诉客户
4.文件包括可执行文件、图像、视频、Office文档、文本
5.健壮性(输入)
6.支持压缩提高效率
7.下次传输根据差异更新文件(中断或结束)
接口
服务器命令行:
1.文件路径名
2.IP地址
3.端口号
客户端命令行:
1.文件路径
2.IP地址
3.端口号
解码器命令行:
client/opt/var 192.168.1.1.9999
开发语言:
C++
评分标准
传输速率、软件质量、图形用户界面