对于linux网络编程,我们都知道UDP是发送数据报,不是面向连接的协议,也就是它只是把数据报发送到链路层,至于能不能到达目的IP和端口,他都无能为力了。而且,我们只要在sendto函数中指定你要发送的端口和IP地址就可以了,我们不用绑定端口和IP。
但是,如果对UDP进行connect函数的调用,会发生什么现象呢?
那么,connect函数是连接外部的IP和端口,一般我们是连接服务器的公共的端口和IP,但是,客户端也可以的!
有了这个能力,我们可以分为两个种:
1,未连接的UDP,新创建的UDP套接字就是这样的。
2,已连接的UDP,调用connect函数就是这样的。
其中,已连接的毕未连接的多了三个变化:
1,我们再也不能给输出操作指定目的IP和目的端口。也就是说,我们不能调用sendto,而是用write或者send。写到UDP的缓冲区里的数据,将自动发送到你调用connect指定的IP和端口。
2,我们不在是用recvfrom获得数据报的发送者,而改成了read,recv或者recvmsg。在一个已连接的套接字上,内核由输入操作返回的数据报只有那些来自connect所指定的协议地址的数据报。目的地为这个已连接的UDP套接字的本地协议地址(IP和端口),发源地却不是该套接字早先connect到得协议地址的数据报,不会投递到该套接字。这样就限制了已连接的UDP套接字能且只能与一个对端交换数据报。
3,由已连接的套接字引发的异步错误发回给他们所在的进程,而未连接的UDP套接字不接受任何异步错误。
但是,我们如果对一个UDP多次调用connect会发生什么情况?
我们得确定为什么我们需要对一个一个UDP多次调用connect?不外乎这两个情况:
1,制定新的IP和端口。
2,断开连接。
第一个目的不同于TCP连接connect的使用:对于TCP连接,connect只能调用一次。
为了断开一个已连接的UDP连接,我们再次调用connect时,把套接字地址结构的地址簇成员(IPv4为sin_family,IPv6为sin6_family),设置为AF_UNSPEC。这么做可能会返回一个EAFNOSUPPORT错误(Address family not supported by protocol ),但是没有关系。使套接字断开的连接的是在已连接的UDP套接字上调用connect的进程。
性能:
当读者给未连接UDP调用sendto的时候,发送超过两个数据报时,内核执行这六个步骤:
1,连接套接字。
2,输出第一个数据报。
3,断开套接字连接。
4,连接套接字。
5,输出第二个套接字。
6,发送第二个数据报。
当读者给已连接的UDP先后两次调用write时,内核执行以下三个步骤:
1,连接套接字。
2,输出第一个套接字。
3,输出第二个套接字。
在这栋情况下,内核就复制一次含有目的IP地址和端口号的套接字地址结构,相反调用两次sendto时,则要复制两次。
临时连接未连接的UDP,需要消耗三分之一的开销。
本文参考:《unix网络编程》,《TCP/IP详解:卷二》