读UNP一书所作的小试验(3)

    本次试验的主题是习题11.9

    该习题的讨论是围绕套接字选项SO_REUSEADDR的。习题中提出的问题可以通过在server程序中调用setsockopt开启SO_REUSEADDR来解决,再次就不多写了。

    试验中发现的问题如下:

    首先说明server端和client端的启动参数(两个程序都在本机运行)

    server:    daytimeudpsrv2     [<hostname/IPaddress>]     <service/port>
    clinet:   daytimeudpcli1        <hostname/IPaddress>      <service/port>

    对于server程序,主机名/IP地址是可选参数。对于server(调用bind)和client(调用conenct),目标既可以用主机名(如 localhost, www.xxx.com的形式)表示,也可以以IP地址字符串(如127.0.0.1,xxx.xxx.xxx.xxx)的形式表示,对于后种方式, IPv4和IPv6地址均可。

    第一次以如下参数启动server和client:
   
    server:      daytimeudpsrv2     192.168.1.29      9877
    client :      daytimeudpcli1       192.168.1.29      9877

    server输出提示信息:datagram from 192.168.1.29:33233,一切OK

    第二次以如下参数启动server和client:
   
    server:      daytimeudpsrv2     localhost      9877
    client :      daytimeudpcli1       127.0.0.1     9877
   
    server输出提示信息:datagram from 127.0.0.1:33233,依旧OK

    第三次以如下参数启动server和client:

    server:      daytimeudpsrv2                           9877   (将udp监听socket邦定至通配地址)
    client :      daytimeudpcli1       127.0.0.1     9877

    server输出提示信息: datagram from [::ffff:127.0.0.1]:33233,发现问题了,为什么输出的IP地址是IPV6的格式?

    查看书中提供的源码,发现问题应该是处在调用getaddrinfo()函数时的参数传递上——出问题的情况下,由于启动参数中未包括邦定地址,传递给getaddrinfo的第一个参数为NULL。问题就处在这里!

    引自书中P275:

    “POSIX声称如果(getaddrinfo)的调用者指定AF_UNSPEC,那么getaddrinfo函数返回适用于主机名和服务名的任意协议族的地址。“

    ”这一声明同时也意味着如果设置了AI_PASSIVE标志,但是没有指定主机名,getaddrinfo()函数返回的链表中讲包括
IPV6通配地址和IPV4通配地址,并且IPV6通配地址在IPV4通配地址之前。这样的顺序安排是有道理的,因为我们将在12.2节看到双栈主机上的IPV6服务器能够同时处理IPV6和IPV4客户。“

    再次查看源码,发现对getaddrinfo()的调用完全符合前面两条所描述的情况,因此,之后调用socket()函数创建的socket的地址族为AF_INET6
,再之后调用Recvfrom得到的客户地址也是IPV6地址(即使client实际使用IPV4地址,也会被自动映射为等价的IPV6地址),所以输出的提示信息为[::ffff:127.0.0.1]:33233,而不是127.0.0.1:33233。

    从另一个方面也可以理解该问题:执行ifconfig -a命令,可以看到实验机器的本机的eth0和lo接口都同时具备ipv4和ipv6地址

    解决该"问题“有两种方法:

    1.在调用getaddrinfo()时将AF_UNSPEC方式修改为AF_INET4,这样就明确只是getaddrinfo()函数只返回ipv4地址。
   
    2.禁用IPV6,在本试验的ubuntu系统中(kernel version 2.6.17.10,内置了对ipv6的支持),方法如下:

   
    sudo gedit /etc/modprobe.d/aliases

    找到下面这行:
 
    alias net-pf-10 ipv6

    在最前面添加“#”把这行注释掉。并填加一行:

    alias net-pf-10 off

    重启后,再次运行server和client,这次提示信息中就不会出现IPV6格式的地址了。

    试验使用的代码为/names/daytimeudpsrv2.c 和 /names/daytimeudpcli1.c

   

你可能感兴趣的:(server,socket,ubuntu,服务器,null)