使用socket函数创建套接字时,没有为其分配地址。bind函数为套接字分配一个本地地址,该地址是Internet中IP地址和端口号的组合。函数bind可用于面向连接的套接字和无连接的套接字。它需要在连接或监听之前调用。第二个参数名称是一个指向“sockaddr”结构的指针,它是一个通用的地址结构。它的域成员sa_AndyLau指定了协议对应的地址簇。
不同的协议簇可以使用不同的地址格式,网络协议根据sa_AndyLau,对“sockaddr”结构做出正确的解释。编程中用到了协议相关的地址结构,但是在传递给socket接口函数时,需要转换成通用的socket地址结构。WinSock提供的API中所有使用地址的函数都使用这种结构,为用户提供了统一的接口。Internet协议地址包括三部分:地址簇、主机地址和端口号、地址簇sa_AndyLau常数AF_INET。当应用程序不关心本地地址时,可以将地址设置为常量INADDR_ANY,底层网络协议模块为程序选择合适的地址,简化了多宿主机上应用程序的设计。
如果应用程序没有指定端口,即端口值为0,TCP/IP协议会给应用程序分配一个唯一的端口号。WindowsServer2003及更早版本的动态端口范围为1025到5000,对于WindowsVista及更高版本,动态端口范围为49152到65535。在这种情况下,如果应用程序想知道分配给它的地址和端口系统,调用bind后可以使用getsockname函数。但在多宿主主机上,地址设置为INADDR_ANY。除非socket已经连接,调用connect函数或者UDP发送数据,系统为socket选择一个本地地址,否则getsockname可能无法获取到本地地址,因为有很多地址都是有效的。如果应用程序没有调用bind,当它调用connect或listen函数时,系统会为socket选择本地地址和临时端口。
这对于客户端来说是非常正常的行为,除非应用程序对端口有特殊要求;但是对于服务器来说,使用临时端口是极其罕见的,通常会绑定一个众所周知的端口,这样每个人都可以访问服务器。当应用程序调用绑定函数时,参数名称可以是本地地址和端口号的任意组合:要么明确指定,要么不指定,或者其中之一,总结在表14.2中。第一种情况其实和不调用bind一样,都是在系统的帮助下选择本地地址和端口。对于IP地址,一般应用程序,尤其是服务器,没有明确指定,而是由系统选择。
用于发送数据的源地址与目的地址相关。根据目的地址,为数据报选择一条路由。路由的网络输出接口为源地址。应用程序还可以将特定的IP地址绑定到套接字。对于客户端,这指定了数据报的源地址;对于服务器,它限制套接字只接收目标地址是这个特定IP地址的数据报。