【问题标题】:Socket programming: bind()-invalid argument套接字编程:bind() - 无效参数
【发布时间】:2015-09-08 04:22:33
【问题描述】:

我正在尝试将我的本地 IPv6 地址绑定到套接字。但总是得到“无效的论点”。我想将特定 IP 地址绑定到套接字的原因是,如果我不绑定错误“No route to host”出现。当我尝试使用下面的命令 ping IPv6 地址时,它不起作用。

ping6 fe80::7ed1:c3ff:fe86

我必须指出我要从哪个接口发送数据包。

ping6 -I en1 fe80::7ed1:c3ff:fe86

这很好用。所以我认为如果我将套接字绑定到接口,那么我可以成功发送数据包。 谁能告诉我如何在不指定接口的情况下发送 IPv6 地址或如何解决这个绑定问题?

这里是代码。

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <netdb.h>

#define LOCALADDR "fe80::7ed1:c3ff:fe86:ddae"

int main(void)
{
int sock,status;
struct addrinfo local_addr;
struct addrinfo *servinfo;
char buffer[1024];

/* create a DGRAM (UDP) socket in the INET6 (IPv6) protocol */
sock = socket(PF_INET6, SOCK_DGRAM, 0);

if (sock < 0) {
    perror("creating socket");
    exit(1);
}

/*Binding specific interface to socket*/
memset(&local_addr, 0, sizeof(local_addr));
local_addr.ai_family = AF_INET6;
local_addr.ai_socktype = SOCK_DGRAM;
local_addr.ai_flags = AI_PASSIVE;

if ((status = getaddrinfo(NULL, "3535", &local_addr, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    exit(1);
}

if (bind(sock, (struct sockaddr *) &local_addr, sizeof(local_addr)) < 0)
    error("ERROR on binding");

我也尝试将“getaddrinfo”中的“NULL”替换为“LOCALADDR”。

if ((status = getaddrinfo(LOCALADDR, "3535", &local_addr, &servinfo)) != 0) {
    fprintf(stderr, "getaddrinfo error: %s\n", gai_strerror(status));
    exit(1);
}

我仍然遇到同样的问题。

我可以成功地将套接字与“in6addr_any”绑定,但随后出现错误“No route to host”。

【问题讨论】:

    标签: c sockets interface bind ipv6


    【解决方案1】:

    这是一个链路本地 IPv6 地址,而不是可路由的 IPv6 地址。链接本地地址特定于链接,并且每个链接可以具有与其他链接相同的地址。例如,如果您有三个不同的接口,您可以为每个接口分配相同的链路本地地址。要使用链路本地地址,您需要指定接口,以便操作系统知道要使用哪个链路。所有接口都将在同一网络中具有链接本地地址:fe80::/10。

    如果您使用可路由的 IPv6 地址,则无需指定接口。

    【讨论】:

      【解决方案2】:

      您创建的套接字不正确。 “域”(第一个参数)应该是 AF_INET6,而不是 PF_INET6。我不确定这些实际上是否会在您的环境中扩展为不同的值,但 AF_* 宏是为此目的而指定的。

      否则,对于接受连接的套接字,您应该以最初呈现的方式获取地址。特别是getaddrinfo() 的文档说

      如果在hints.ai_flags 中指定了AI_PASSIVE 标志,并且node 为NULL,则返回的套接字地址将适合bind(2) 的套接字,该套接字将accept(2) 连接.返回的套接字地址将包含“通配符地址”(INADDR_ANY 用于 IPv4 地址,IN6ADDR_ANY_INIT 用于 IPv6 地址)。通配符地址由打算接受任何主机网络地址上的连接的应用程序(通常是服务器)使用。如果 node 不为 NULL,则忽略 AI_PASSIVE 标志。

      因此,您当然可以并且可能应该指定一个 NULL 第一个参数。

      但是请注意,getaddrinfo() 返回地址的链接列表,在某些情况下,有必要选择与第一个不同的地址列表。不过,我认为在这种特殊情况下,第一个应该没问题。

      还请注意,来自尝试连接的客户端的“无路由到主机”消息不一定表示服务器未在侦听。很可能是客户端使用了错误的地址(参见@RonMaupin 的答案),或者正如它所说,没有(已知的)从客户端到服务器的网络路由。例如,由于路由器或防火墙配置,可能会出现这种情况。

      【讨论】:

      • "'domain'(第一个参数)应该是 AF_INET6,而不是 PF_INET6" 并不是每个平台都这样;在 OS X “man”状态下,您应该使用 PF_*-ones。
      • @K.Biermann,Apple 自己的在线手册页(12)对此有所不同,但POSIX docs 指的是sys/socket.h 的符号,并且该标题是必需的提供AF_INET6 和朋友,但根本没有提到PF_* 符号。
      • @K.Biermann,因此,如果您想编写 可移植 代码,请使用 AF_* 常量。如果您的平台定义的 PF_* 常量的值与相应的标准 AF_* 常量不同,或者它根本不提供 AF_* 常量,那么是时候考虑找一份不需要为此开发的工作了不正常的环境。但我不认为 OS X 属于这一类。
      • 我使用了终端的 man,它只有 section-2-manpage。我想我会提交一份错误报告;谢谢?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-06-29
      • 2013-01-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-05
      相关资源
      最近更新 更多