关于udp的一些问题总结

 

socket 的端口号

客户端的 socket 很少调用 bind() 来指明 socket 的端口号。 相反通常是让操作系统自动分配一个端口号。

TCP客户端 socket 的端口号是在调用了 connect() 之后,系统 会自动分配端口号。

UDP客户端 socket 的端口号是在第一次调用 sendto() 之后, 系统会自动分配端口号。

如果 UDP 的端口是自动分配的话,那么系统不会再改变这个端 口号。如果 UDP 的IP 地址也是自动分配的话,那么每一次调用 sendto() 系统都可能会根据目的 IP 地址而改变源IP地址。

weak end system VS strong end system

网络接口会接收所有和本地 IP 地址一致的数据包,叫做 weak end system .

网络接口只会接收所有和本接口的 IP 地址一致的数据包,叫做 strong end system 。

不同点, 在一个 multihome 的主机有多个网络接口,那么 strong end system 的过滤检查会更强大一些。

UDP 发送数据的地址和接收数据的地址不一致的问题。

UDP 的客户端发送给服务器,如果服务器的用于接收的网络接口 有多个 IP 地址,那么服务器送响应的时候就会自动选择一个 primary IP 地址回送给客户端。primary IP 地址有可能和客户 端发送的 IP 地址不一样。

如果客户端根据接收的响应的 IP 地址来判断是否是服务器发送 的响应,那么就有可能出错。

解决办法,一个是改造客户端,不再用 IP 地址判断是否是一个 服务器发送的数据包,而是根据 DNS 得到的域名来判断。缺点 是系统一定要有域名服务器,而且查询域名会影响效率。 一个办法是服务器不是用 wildcard 来绑定 socket ,而是为每 一个 IP 地址绑定一个 socket 。 缺点是系统如果动态改变了 IP 地址就需要重新起动服务器,而且增加服务器必须 select() 检查所有的 socket 。

UDP ICMP

sendto() 成功返回后,意思是说主机的网络接口有足够的缓冲 队列空间,用以容纳下要发送的数据。

如果接收端回送 ICMP 消息,那么是 socket 不能够知道的,除 非 UDP socket 也调用了 connect() 变成了 connected UDP socket.

linux 的实现中,则会 unconnected socket 也会返回 ICMP 错 误,只要 SO_BSDCOMPAT socket option 没有置位。

ICMP 消息会在下一个 read() 中返回, 错误值是 ECONNREFUSED。

有些 System V 系统有 Bug ,不会为 connected socket 返回 ICMP 错误。

connected UDP socket VS unconnected UDP socket

调用了 connect() 函数的 UDP socket 就从 unconnected UDP socket 变成了 connected UDP socket 。

connect() 并不是真正建立连接,只是把 socket 和一个 peer name 联系在一起。

函数 connect() 函数的操作完全是本地操作, 不涉及网络。

系统会根据 connect() 函数指定的目的地址寻找网络接口,选 择该网络接口的 primary IP 地址作为本地地址。

不同点:

  1. connected socket 调用 send 而不是 sendto 。
  2. connected socket 调用 recv 而不是 recvfrom 。 只有目的地址 和 connect() 函数指定的地址一致才会被接收到。
  • 问题:如果系统也是根据 IP 地址来判断一个连接的话,那么也有可能出现 上面说的发送命令的目的地址和接收响应的源地址是不一样的问题。
  • 答案:只有改造服务器了。
  1. ICMP 错误会收到。
  2. 发送数据的时候,由于不用指定目的 IP 地址,在用户程序 和内核之间传递的数据少,所以效率稍微高一些。

connected UDP socket 是否可以再调用 connect()

和 TCP 不一样,connected socket 可以多次调用 connect()。

connect() 的目的地址中的 address family 如果是 AF_UNSPEC 那么 connected socket 会变成 unconnected socket 。

可能会返回 EAFNOSUPPORT ,但是没有关系。

 

 

 

 

发表评论