序言
本文补充介绍UDP Socket高级编程和一些UDP Socket零散知识。
1. 零散知识点补充
[1]. 乱序问题
现象:
- 乱序就是发送数据的顺序和接收数据的顺序不一致,例如发送数据的顺序为A、B、C,但是接收到的数据顺序却为:A、C、B。
原因:
- UDP不保证可靠接收。
- 每个数据报走的路由并不一样,有的路由顺畅,有的却拥塞,导致每个数据报到达目的地的顺序不一样。
解决方法:
- 使用RTP协议加入顺序控制机制(sequence number,序列号)
[2]. UDP缓冲区
现象:
- 使用默认UDP接收缓存,发生UDP丢包
原因:
- 数据包发送过快或数据包过大导致
解决方法:
关于UDP缓冲区的两点说明:
UDP缓冲区有接收缓冲区和发送缓冲区,大小有默认值,最小值和最大值
内核使用的UDP缓冲区是环形缓冲区,通过修改默认值和setsocketopt修改,增大了接收队列
[3]. UDP接收机制
socket一次能够send的UDP数据长度
- UDP报头长度字段2字节,16比特,最长65535B即64K,考虑到UDP报头长度8字节,IP报头20字节,socket一次发送的长度不能超多65535 - 28 = 65507,否则返回错误
UDP接收机制
recvfrom接收一次一个包,接收失败返回-1,接收成功返回数据包长度
- 不会只返回包的一部分,包不完整会丢弃整个数据包
比如发端发送两个长度分别为300B,200B字节,则recvfrom接收返回值为300,200或200,300
[4]. 阻塞和非阻塞接收
UDP接收函数:recvfrom
TCP接收函数:recv
阻塞接收
数据到来进行接收
- TCP:缓冲区至少有一个字节
- UDP:缓冲区至少有一个完整的数据报
没有数据处于睡眠状态
非阻塞接收
数据到来进行接收
- TCP:缓冲区有任何一个字节则返回数据大小
- UDP:缓冲区有一个完整的数据报,返回接收到的数据大小
没有数据返回错误码
2. UDP Socket高级编程
[1]. UDP套接字
UDP套接字分类
我们知道,TCP客户端有connnect()函数,在UDP中其实也有connect函数,UDP网络编程中的connect函数仅用于表示确定了另一方的地址,并没有其他含义。据此可以将UDP套接字分为
未连接的UDP套接字(未使用connect函数进行地址确认的UDP连接),也就是我们常用的UDP套接字
- 使用sendto/recvfrom进行信息的收发,目标主机的IP和端口是在调用sendto/recvfrom时确定
已连接的UDP套接字
- 对于已连接的UDP套接字,必须先经过connect来向目标服务器进行指定,然后调用read/write进行信息的收发,目标主机的IP和端口是在connect时确定的,也就是说,一旦conenct成功,我们就只能对该主机进行收发信息了
发包效率
未连接的UDP套接字,两个数据报调用sendto函数,内核将执行以下六个步骤
- 连接套接字
- 输出第一个数据报
- 断开套接字连接
- 连接套接字
- 输出第二个数据报
- 断开套接字连接
已连接的UDP套接字,两个数据报调用write函数,内核将执行以下三个步骤
- 连接套接字
- 输出第一个数据报
- 输出第二个数据报
由此可见,当应用进程给同一个目的地址发送多个数据报时,连接套接字效率更高
[2]. 基于connect的套接字通信框架
- 客户端/服务器通信框架
- 基于connect的套接字通信,与常用的UDP套接字通信相比,只是多了一个connect的过程。如下
void UdpHandler(int socketfd, struct sockaddr* dest)
{
char buf[1024] = "UDP Socket Test!";
int len = 0;
connect(socketfd, dest, sizeof(*dest);
len = write(socketfd, buf, 1024);
read(socketfd, buf, len);
}
Acknowledgements:
http://www.cnblogs.com/skyfsm/p/6287787.html?utm_source=itdadao&utm_medium=referral
http://blog.csdn.net/hairetz/article/details/17968383
2017.09.24