【问题标题】:connect() returns "invalid argument" with ipv6 addressconnect() 返回带有 ipv6 地址的“无效参数”
【发布时间】:2012-08-28 21:47:03
【问题描述】:

我有这个简单的客户端-服务器应用程序对。代码非常简单,我只使用新的、建议的方法,如 getaddinfo 等,一切都适用于 ipv4。即使对于 ipv6 环回 (::1) 它也有效。当涉及到其他一些 ipv6 地址时,问题就开始了......我在网络中有两台机器,当我传递它们的 ipv4 地址时一切正常,但是当我给我的客户端 ipv6 地址时,我在连接函数上得到一个错误:无效参数. 嘿,我不是已经知道了吗?我愿意!当我尝试 ping6 这个 ipv6 地址时,我得到了同样的错误:

连接:无效参数

但是有一种方法可以克服这个障碍——人们应该选择一个带有 -I 开关的接口,从那时起它就可以顺利运行了。但是我怎样才能在我的客户端应用程序中实现同样的效果呢?我该怎么办?我的客户端代码如下所示:

struct addrinfo hints;
struct addrinfo *server;

memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;

int status;
if((status = getaddrinfo(argv[1], argv[2], &hints, &server) != 0))
{
    perror("getaddrinfo error");
    return 1;
}

int sock_fd;
struct addrinfo *ptr;
for(ptr=server;ptr!=NULL;ptr=ptr->ai_next)
{
    if( (sock_fd = socket(ptr->ai_family,ptr->ai_socktype,ptr->ai_protocol)) == -1)
    {
        perror("socket error");
        continue;
    }
    if( connect(sock_fd, ptr->ai_addr,ptr->ai_addrlen) == -1 )
    {
        perror("connect error");
        continue;       
    }
    break;
}

【问题讨论】:

  • ping 拒绝的这个有问题的地址是什么?
  • 我正在 ping 我网络中的另一台机器,但它对所有 ipv6 地址的工作方式相同 - 请检查:lists.debian.org/debian-ipv6/2005/06/msg00044.html
  • @flyjohny 也许你应该检查你的路由,看看默认路由是否是 ip6 路由命令:“route -A inet6”

标签: c++ c arguments connect


【解决方案1】:

ff... 开头的地址是多播地址。将流连接到多播地址不起作用。

fe80... 开头的地址是链接本地地址,它们具有与之关联的接口标识符。试试看getaddrinfo返回的sockaddrscope字段填了吗?

【讨论】:

  • 此字段应包含接口编号。您是否使用%eth0%1(1 为接口编号,您可以使用ip 工具查找)符号指定范围?\
  • 不。当我这样做时,这个范围字段填充了一些值并且它似乎可以工作(虽然我需要配置我的特定固件,但我不再得到无效参数)。但我似乎错过了一些东西,在我阅读的所有与 ipv6 相关的材料中,我没有遇到过这个 - 每当我使用链接本地地址时,我是否需要指定接口?
  • 是的,你知道。链路本地地址恰恰意味着地址的唯一性只在该特定链路上得到保证,因此除非您告诉系统,否则系统无法找出将数据发送到哪个接口。另一种方法是分配具有全局范围的地址并使用路由表。
  • @SimonRichter - 如果我使用本地链接地址,是否意味着 scope_id 字段将始终为 0,我们需要明确指定它?系统可以使用 /etc/hosts 中的任何配置自动选择它吗? (注意:我的网络中没有 DNS)
  • @kaps,不,没有办法让系统自动选择接口。将ppp0ppp1ppp2 全部配置为使用fe80::1 的本地地址和fe80::2 的对等地址是完全合法的,因此操作系统无法决定将哪个接口用于目标fe80::2的地址。所以程序需要填写scope_id。当地址由用户配置时,getaddrinfo 将在用户使用% 表示法时填写,当您使用多播进行发现时,您可以使用发现数据包来源的作用域ID。
【解决方案2】:

您需要指定 IPv6 ping 的接口(即 -I eth0):

ping6 -I eth0 fe80::208:54ff:fe34:22ae

使用本地链路地址进行 IPv6 ping,需要定义它必须发送/接收数据包的设备 - 每个设备都有一个本地链路地址。

尝试不使用它,将导致错误消息如下:

--> # ping6 fe80::208:54ff:fe34:22ae 
connect: Invalid argument

在这种情况下,您必须另外指定接口,如下所示:

--> # ping6 -I eth0 fe80::208:54ff:fe34:22ae
PING fe80::208:54ff:fe34:22ae(fe80::208:54ff:fe34:22ae) from fe80::208:54ff:fe34:22ae eth0: 56 data bytes
64 bytes from fe80::208:54ff:fe34:22ae: icmp_seq=0 ttl=64 time=0.027 ms
64 bytes from fe80::208:54ff:fe34:22ae: icmp_seq=1 ttl=64 time=0.030 ms
64 bytes from fe80::208:54ff:fe34:22ae: icmp_seq=2 ttl=64 time=0.036 ms

您必须在客户端 APP 中遵循的类似方法..

【讨论】:

    【解决方案3】:

    我的建议是你在接口/网络连接中开启IP6协议,如果仍然有错误,另外扔掉ip4协议。

    在我的 Linux Box 上,当我的 ip4 接口处于活动状态并且我的应用程序尝试将 ip4 接口与 ip6 设置一起使用时,也会发生这种情况。对于 windows 也应该同样有效。

    如果有不清楚的地方问。

    【讨论】:

    • 我知道我很懒,但是你能告诉我如何在界面中打开ip6协议吗?我正在使用 Linux 机器。
    • 首先查看本指南tldp.org/HOWTO/Linux+IPv6-HOWTO/x790.html,然后在您的特定接口上尝试:ping6 -I eth0 "fill the ip6addr here" 这可能是您的环回接口激活了 ip6 支持,因此本地 ping没有问题,你能告诉我们你的 Linux 发行版和内核版本吗?
    猜你喜欢
    • 2017-03-07
    • 2023-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多