说起套接字的通讯,我们一般会想到C/S结构(客户端/服务端结构),从应用的角度来讲,确实如此,比如IM(即时通讯)服务,一台IM服务器同时与几
万的IM客户端进行着UDP数据报的通讯。但我们从套接字的编程实现,以及TCP/IP协议栈的实现原理这一层上来看,并不存在着服务端与客户端的明显区
别。
网络上的两台主机(为简化起见,我们假设它们处于同一子网内,并能互相连通),为了建立一个UDP的通讯,一端A必须事先知道另一端B的端口(B有一个进
程可以接受UDP数据报)。即B必须先建立一个套接字,并自己为其选择一个固定的端口号,而不是让系统自动选择,并把这个端口号告知A(通过人,或者是熟
知端口)。然后A就可以通过connect系统调用,在其socket上设置好相应参数,以后每个发出的数据包的UDP首部中总标明目的地址B和其相应的
端口号;或者每发一个数据报,通过sendto传入B的地址和端口号,以确保每个发出的数据报在B端被正确的进程接收。
而A端可以自己选择一个固定的端口号,也可以由系统自动选择,这并不重要。因为B端收到来自A端的第一个数据报后,可以从UDP首部中判断A端的端口号,
并在回应包中进行正确设置。在这样的情况下,我们一般就认为B是服务端,A是客户端。它们的唯一区别在于服务端的端口号必须是事先被客户端知道的。而客户
端的端口号的选择则相对比较随便。
我们前面文章提到过协议栈中的函数myudp_v4_get_port可以为一个UDP套接口选择一个可以使用的端口号,也可以由我们自己选择一个端口号,然后由该函数判断是否可用。我们通过bind系统调用选择一个固定的端口号:
int bind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen);
sockfd是套接字描述符,会被转化为相应的套接字结构体,my_addr和addrlen是要绑定的地址和地址长度。地址包括IP地址(标明主机)和端口号(标明进程)。
UDP协议没有自己的bind函数,直接使用了MY_INET域的通用bind函数。我们通常绑定的地址是INADDR_ANY,这是一个全零地址,表示
对本机接收地址不作限制,即对端可以通过本机的任何一个网络设备接口向本进程发送UDP数据报,这个IP地址被赋给套接字结构体的成员rcv_saddr
和saddr,这两个成员分别表示绑定的本机IP地址和发送数据报时的本机源IP地址。为INADDR_ANY,表示发送时根据对端IP地址,通过查询路
由表获得本机源IP地址。但端口必须由应用程序指定,这样才使bind系统变得有意义,当然,也可以设定端口为0,让协议栈自动选择,但这样,bind调
用不调用变得没有任何区别了(connect或myinet_sendmsg函数在发现端口没有绑定时,会执行自动绑定的)。对于端口绑定还有一个限制,
即要绑定的端口小于1024(PROT_SOCK)时,用户必须有相应的权限才能执行绑定,因为小于1024的端口一般为系统服务保留。
最后,设置目的IP地址和目的端口为0,表示对对端不作任何限制。
阅读(1241) | 评论(0) | 转发(1) |