套接字编程:bind()-无效参数

Socket programming: bind()-invalid argument

我正在尝试将本地 IPv6 地址绑定到套接字。但是总是得到"invalid argument"。我想将特定 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"。

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

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

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

否则,对于接受连接的套接字,您应该以与第一次出现的方式大致相同的方式获得地址。特别是 getaddrinfo() 的文档说

If the AI_PASSIVE flag is specified in hints.ai_flags, and node is NULL, then the returned socket addresses will be suitable for bind(2)ing a socket that will accept(2) connections. The returned socket address will contain the "wildcard address" (INADDR_ANY for IPv4 addresses, IN6ADDR_ANY_INIT for IPv6 address). The wildcard address is used by applications (typically servers) that intend to accept connections on any of the hosts’s network addresses. If node is not NULL, then the AI_PASSIVE flag is ignored.

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

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

另请注意,来自尝试连接的客户端的 "no route to host" 消息并不一定表示服务器未在侦听。很可能是客户端使用了错误的地址(c.f。@RonMaupin 的回答),或者正如它所说,没有(已知的)从客户端到服务器的网络路由。例如,这可能是由于路由器或防火墙配置引起的。