上一篇我们提到,除非套接字已连接,否则异步错误是不会返回到UDP套接字的。我们确实可以给UDP套接字调用connect,然而这样做的结果却与TCP连接大相径庭:没有三次握手。内核只是检查是否存在立即可知的错误(例如一个显然不可达的目的地),记录对端的IP地址和端口号(取自传递给connect的套接字地址结构),然后立即返回到调用进程。
有了这个能力后,我们必须区分:
(1)未连接UDP套接字,新创建UDP套接字默认如此;
(2)已连接UDP套接字,对UDP套接字调用connect的结果。
对于已连接UDP套接字,与默认的未连接UDP套接字相比,发生了三个变化:
(1)我们再也不能给输出操作指定目的IP地址和端口号。也就是说,我们不使用sendto,而改用write或send。写到已连接UDP套接字上的任何内容都自动发送到由connect指定的协议地址(例如IP地址和端口号)。(其实我们可以给已连接UDP套接字调用sendto,但是不能指定目的地址。sendto的第五个参数必须为空,第六个参数应该为0)。
后面有在ubuntu 10.04系统下的验证。
(2)我们不必使用recvfrom以获悉数据报的发送者,而改用read,recv或recvmsg。在一个已连接UDP套接字上,由内核为输入操作返回的数据报只有那些来自connect所指定协议地址的数据报。(确切的说,一个已连接的UDP套接字仅仅与一个IP地址交换数据报,因为connect到多播或广播地址是可能的)。
(3)由已连接的UDP套接字引发的异步错误会返回给他们所在的进程,而未连接UDP套接字不接受任何异步错误。
应用进程首先调用connect指定对端的IP地址和端口号,然后使用read和write与对端进程交换数据。来自任何其他IP地址或端口的数据报(上中我们用“???”表示)不投递给这个已连接套接字,因为他们要么源IP地址要么源UDP端口不与该套接字connect到的协议地址相匹配。这些数据报可能投递给同一个主机上的其他某个UDP套接字。如果没有相匹配的其他套接字,UDP将丢弃他们并生成相应的ICMP端口不可达错误。
1.给一个UDP套接字多次调用connect
拥有一个已连接UDP套接字的进程可出于下列两个目的之一再次调用connect:
指定新的IP地址和端口号;
断开套接字。
第一个目的(即给一个已连接UDP套接字指定新的对端)不同于TCP套接字中的connect的使用:对于TCP套接字,connect只能调用一次。
为了断开一个已UDP套接字连接,我们再次调用connect时把套接字地址结构的地址族成员(sin_family)设置为AF_UNSPEC。使套接字断开连接的是在已连接UDP套接字上调用connect的进程。
查看本栏目更多精彩内容:http://www.bianceng.cnhttp://www.bianceng.cn/OS/unix/