2015-06-22 39 views
0

我试图将我的本地IPv6地址绑定到套接字。但总是得到“无效论证”。我想将特定IP地址绑定到套接字的原因是,如果我不绑定错误“无路由到主机”出现。当我尝试用下面的命令ping一个IPv6地址时,它不起作用。套接字编程:bind() - 无效的参数

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”。

回答

0

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

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

0

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

否则,对于接受连接的套接字,您应该获得一个地址,这与您首次出现的方式非常相似。特别地,对于getaddrinfo()文档说

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

因此,你当然可以或许应该指定一个NULL第一个参数。

但是,请注意,getaddrinfo()会返回地址的链接列表,并且在某些情况下,需要选择与第一个不同的地址。不过,我认为首先应该在这种特殊情况下罚款。

请注意,尝试连接的客户端的“无路由到主机”消息并不一定表示服务器未在侦听。很可能是客户使用错误的地址(c.f. @ RonMaupin的回答),或者正如它所说的那样,从客户端到服务器之间没有(已知的)通过网络的路由。例如,这可能是由于路由器或防火墙配置引起的。

+0

“'域'(第一个参数)应该是AF_INET6,而不是PF_INET6” 这在每个平台上都不是这样;在OS X“man”状态下,你应该使用PF _ * - 。 –

+1

@ K.Biermann,苹果自己的在线手册页([1](https://developer.apple.com/library/ios/documentation/System/Conceptual/ManPages_iPhoneOS/man2/socket.2.html),[2] (https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/socket.2.html))不同,但[POSIX docs](http://pubs.opengroup。 org/onlinepubs/009695399/functions/socket.html)引用了符号的sys/socket.h,并且该头文件需要提供AF_INET6和朋友,但没有提及PF_ *符号在所有。 –

+1

@ K.Biermann,如果你想编写* portable *代码,所以你使用'AF_ *'常量。如果您的平台使用与相应的标准AF_ *常量不同的值定义了'PF_ *'常量,或者它根本不提供'AF_ *'常量,那么是时候考虑找到一个不需要的工作开发这样一个不正常的环境。但我不认为OS X属于这一类。 –