UDP 连接

1. UDP connect

我们经常说UDP是无连接的传输协议, 如果UDP调用connect呢? 会发生什么?
UDP套接字调用connect函数, 跟TCP连接调用connect不一样: 没有三次握手过程. 而且, 内核只是检查是否存在立即可知的错误(e.g. 一个显然不可达的目的地, 由于非法端口/ip地址等原因), 记录对端的IP地址和端口号(取自传递给connect的套接字地址结构), 然后立即返回到调用进程.
用sockname是本地协议地址, peername是对端协议地址, 那么UDP connect(已连接UDP套接字)更好的名字是setpeername, UDP bind更好的名字是setsockname.

因此, UDP connect并不是在通信两端之间真正建立了可靠连接, 而只是设置对端协议地址.

1.1 UDP连接的概念

  • 未连接UDP套接字(unconnected UDP socket), 新创建UDP套接字默认;
  • 已连接UDP套接字(connected UDP socket), 对UDP套接字调用connect的结果;

1.2 未连接UDP套接字 与 已连接UDP套接字

已连接UDP套接字在未连接UDP套接字 (默认)基础上, 发生了变化:
1)不能给输出操作指定目的IP地址和端口号. i.e. 不能使用sendto(传入目的地址结构, 如果非要使用sendto, 地址结构参数必须为NULL), 而改用write或read. 因为写已连接UDP套接字上的任何内容, 都自动发送到由connect指定的对端协议地址(IP地址+端口号);

TCP和UDP套接字: 可指定目的协议地址吗?

套接字类型 write或send 不指定目的地址的
sendto
指定目的地址的
sendto
TCP套接字 可以 可以 EISCONN
UDP套接字, 已连接 可以 可以 EISCONN
UDP套接字, 未连接 EDESTADDRREQ EDESTADDRREQ 可以

2)不必使用recvfrom以获取数据报的发送者, 改用read, recv或recvmsg.
缺点: 内核返回的数据报, 只有那些来自connect所指定对端协议地址的数据报. 也就是说, 接收到的数据报中, 如果源地址 != connect指定对端地址, 则进程不会接收到.

问题: 进程不收到的UDP报文, 会如何处理?
可能投递到同一主机上的其他某个UDP套接字. 如果没有相匹配的其他套接字, UDP将丢弃并生成相应的ICMP不可达错误.

3)由已连接UDP套接字引发的异步错误会返回给它们所在的进程, 而未连接UDP套接字不接收任何异步错误.

小结
UDP套接字何时调用connect?
当UDP客户进程或服务器进程只使用自己的UDP套接字与确定的唯一对端进行通信时, 才调用connect. 调用connect的通常是UDP客户, 少数情况下可能UDP服务器, 如UDP服务器与单个客户长时间通信(TFTP).

1.2 多次调用connect

一个已连接UDP套接字的进程, 何时可以再次调用connect?

  1. 指定新的IP地址和端口号;
  2. 断开套接字;

注意: 对于TCP套接字, 只能调用一次connect.

对于1), 类似于第一次调用connect方式, 为connect指定新的IP地址和端口号;
对于2), 再次调用connect时, 需要把套接字地址结构中的地址族成员(IPv4为sin_family, IPv6为sin6_family) 设置为AF_UNSPEC. 可能返回EAFNOSUPPORT错误, 不过没关系, 忽略即可.
不同Unix变体可能有多种办法断开连接, 不过, 用AF_UNSPEC传递给connect的sa_family是最通用的方法.

而且, man connect(2)提到, 断开套接字连接, 应该用AF_UNSPEC传递给connect的sa_family

Generally, connection-based protocol sockets may successfully connect() only once; connectionless
protocol sockets may use connect() multiple times to change their association. Connectionless
sockets may dissolve the association by connecting to an address with the sa_family member of
sockaddr set to AF_UNSPEC (supported on Linux since kernel 2.2).

1.3 性能

多次发送数据时, 已连接UDP套接字效率 > 未连接UDP套接字效率.

UNP 8.11.2提到, 临时连接未连接的UDP套接字大约会耗费每个UDP传输三分之一的开销.

以2次发送数据报为例,
未连接UDP套接字调用2次 sendto发送数据报, 然后断开连接. 执行步骤:
1)连接套接字;
2)输出第一个数据报;
3)断开套接字连接;
4)连接套接字;
5)输出第二个数据报;
6)断开套接字连接;

内核复制2次IP地址+端口号

已连接UDP套接字调用1次connect连接, 2次write发送数据报. 执行步骤:
1)连接套接字;
2)输出第一个数据报;
3)输出第二个数据报;

内核复制1次IP地址+端口号

posted @ 2021-06-08 15:06  明明1109  阅读(2451)  评论(0编辑  收藏  举报