基于UDP的通信过程:
客户端和服务端区分不明显!即不做区分!
基本流程是:
- socket创建套接字
- 仅绑定端口号(绑定端口是可选项)
- 发送数据或者接收数据
- 关闭socket服务
- UDP数据包格式:
![image]()
![image]()
- 读写请求:
操作码 |
文件名 |
0 |
模式 |
0 |
2Bytes |
若干Bytes |
1B |
若干字节 |
1B |
- 数据包:
- ACK:
- ERROR:
操作码 |
差错码 |
差错信息 |
0 |
2B |
2B |
若干字节 |
1B |
- 等于1:表示下载请求
- 等于2:上传请求
- 等于3:表示本次报文为数据包
- 等于4:表示本次报文为ACK信息
- 等于5:本次报文为出错信息
2. 常用struct符号含义:
符号 |
对应C语言类型 |
数据大小 |
H |
unsigned short |
2个字节 |
b |
signed char |
1个字节 |
s |
char |
一个字节 |
3. 常用符号图示:
![image]()
![image]()
4. struct模块:
- 实现对数据的封装与拆分,把若干数据封装成一个符合5类报文格式要求的类结构体
- 常用函数:pack, unpack, cmdTuple
- pack(fmt, v1, v2, ...)
按照给定的格式(fmt),把数据封装成字符串(实际上是类似于c结构体的字节流)
按照给定的格式(fmt)解析字节流string,返回解析出来的tuple
计算给定的格式(fmt)占用多少字节的内存
-
实例:
struct.pack(“!H8sb5sb”,1,“test.jpg”,0,“octet”,0)
struct.pack("!HH",4,p_num)
cmdTuple = struct.unpack("!HH", recvData[:4])
- 第一行:表示一个下载请求,文件名是test.jpg,模式是octet
5个字段的大小分别为:H即为2字节,8s即为8字节,b即为1字节,5s即为5字节,b即1字节。即:操作码字段内容为1大小为2字节,文件名字段内容为test.jpg大小为8字节,0字段内容为0大小为1字节,模式字段内容为octet大小为5字节,0字段内容为0大小为1字节
type |
操作码 |
文件名 |
0 |
模式 |
0 |
内容 |
1(下载请求) |
test.jpg |
0 |
octet |
0 |
大小 |
2字节 |
8字节 |
1字节 |
5字节 |
0字节 |
然后将之封装成一个字符流,即可发送到网络。
|
|
|
|
|
|
- 第二行:大端模式,是一个ACK信息。操作码字段的内容为4即标识本报文为ACK,块编号字段的内容为
p_num
,操作码字段的大小为2字节,块编号字段的大小也为2字节。
之后就可以pack,。
- 第三行:大端模式,有两个字段,分别为2字节,根据这个来解包。把得到的两个字段拼接成一个tuple返回给
cmdTuple
。后面再根据ACK的格式分析字段的内容与大小是否正确,进一步判断本报文是否为ACK信息或者错误包。(比如:如果是ACK信息,那么这两个字段第一个字段必然是操作码且内容为4,第二个字段必然是块编号,其值根据程序来判断)
两件事:
- 如果当前数据包的数据部分小于512字节,那么可以给服务器发ACK,表示文件已经传完,可以关闭ftcp连接了。
- 每当客户端接收了一个数据包,就要给服务端返回一个ACK确认。