UDP传输的过程类似于寄信。
数据报是独立的一整个,应用层交给 UDP 多长的报文,UDP原样发送,既不会拆分,也不会合并。
例如:用 UDP 传输 100 个字节的数据:
如果发送端调用一次 sendto,发送100个字节,那么接收端也必须调用对应的一次recvfrom,接收100字节。
而不能循环调用10次recvfrom, 每次接收10个字节。
UPD 的协议报头长度是 固定的 8字节。
16位 UDP 长度,表示整个数据报(UDP 首部 + UDP 数据)的 最大长度,即 216 = 64kb。
如果校验和出错, 就会直接丢弃。
报头(协议)的本质其实就是:结构化数据(结构体、位段)
// 结构体实现
struct udp_header
{
uint16_t src_port;
uint16_t dst_port;
uint16_t udp_len;
uint16_t check;
};
// 位段实现
struct udp_header
{
uint32_t src_port:16;
uint32_t dst_port:16;
//...
};
封装
char* p
指针指向一个缓冲区,前面放 UDP 结构报头(固定 8 字节),后面放有效载荷,对报头内容的填充就可以写作:((struct udp_header*)p)->src_port = xx;
((struct udp_header*)p)->dst_port = xx;
((struct udp_header*)p)->udp_len = xx;
((struct udp_header*)p)->check = xx;
封装
char* p
指针指向一个缓冲区,前面放 UDP 结构报头(固定 8 字节),后面放有效载荷,对报头内容的填充就可以写作:((struct udp_header*)p)->src_port = xx;
((struct udp_header*)p)->dst_port = xx;
((struct udp_header*)p)->udp_len = xx;
((struct udp_header*)p)->check = xx;
UDP 没有真正意义上的 发送缓冲区。调用 sendto 会直接交给内核,由内核将数据传给网络层协议进行后续的传输动作。
UDP 具有接收缓冲区。但是这个接收缓冲区不能保证收到的 UDP 报的顺序和发送 UDP 报的顺序一致。如果缓冲区满了,再到达的UDP数据就会被丢弃。
UDP 的 socket 既能读,也能写, 这个概念叫做 全双工