[英]Resolve and bind to IPv6 address
我編寫了一個程序來解析地址或主機名,然后嘗試在listen(2)
模式下綁定到該地址。 出於某些奇怪的原因,我無法使用IPv6地址,該程序在調用bind(2)
后僅以“無效參數”失敗。 使用IPv4,一切都可以按我預期的方式工作,名稱得到解析,地址僅轉換為二進制格式。
資源
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <netdb.h>
#include <unistd.h>
static int
resolve_addr (const char *hostname, const char *service, int family, struct addrinfo **result)
{
struct addrinfo addr_hint;
memset (&addr_hint, 0, sizeof (struct addrinfo));
addr_hint.ai_socktype = SOCK_STREAM;
addr_hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ADDRCONFIG;
addr_hint.ai_family = family;
return getaddrinfo (hostname, service, &addr_hint, result);
}
int
main (int argc, char *argv[])
{
struct addrinfo *addr;
int rval, sock, opt_val;
rval = resolve_addr (argv[1], argv[2], AF_UNSPEC, &addr);
if ( rval != 0 ){
fprintf (stderr, "%s\n", gai_strerror (rval));
return 1;
}
sock = socket (addr->ai_family, addr->ai_socktype | SOCK_NONBLOCK, addr->ai_protocol);
if ( sock == -1 ){
fprintf (stderr, "error socket: %s\n", strerror (errno));
return 1;
}
if ( setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof (opt_val)) == -1 ){
fprintf (stderr, "error setsockopt: %s\n", strerror (errno));
return 1;
}
if ( bind (sock, (struct sockaddr*) addr->ai_addr, sizeof (struct sockaddr)) == -1 ){
fprintf (stderr, "error bind: %s\n", strerror (errno));
return 1;
}
if ( listen (sock, 32) == -1 ){
fprintf (stderr, "error listen: %s\n", strerror (errno));
return 1;
}
sleep (120);
freeaddrinfo (addr);
close (sock);
return 0;
}
用法
./test_bind localhost 8888 # works
./test_bind 0.0.0.0 8888 # works
./test_bind 127.0.0.1 8888 # works
./test_bind :: 8888 # does not work: Invalid argument
./test_bind ::1 8888 # does not work: Invalid argument
邊注
我使用netcat來確定系統是否有問題,但是以下命令可以運行:
ncat -l :: 8888
在netstat中可以看到:
tcp6 0 0 :::8888 :::* LISTEN
我更新了代碼,IPv4和IPv6均已解析並成功綁定。問題出在bind(2)
函數的第三個參數中,該參數根據結構大小計算地址的大小,而不是使用getaddrinfo
的值結果。
我替換了該行:
if ( bind (sock, (struct sockaddr*) addr->ai_addr, sizeof (struct sockaddr)) == -1 ){
有:
if ( bind (sock, (struct sockaddr*) addr->ai_addr, addr->ai_addrlen) == -1 ){
全文
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netdb.h>
#include <unistd.h>
static int
resolve_addr (const char *hostname, const char *service, int family, struct addrinfo **result)
{
struct addrinfo addr_hint;
memset (&addr_hint, 0, sizeof (struct addrinfo));
addr_hint.ai_socktype = SOCK_STREAM;
addr_hint.ai_flags = AI_PASSIVE | AI_NUMERICSERV | AI_ADDRCONFIG;
addr_hint.ai_family = family;
return getaddrinfo (hostname, service, &addr_hint, result);
}
int
main (int argc, char *argv[])
{
struct addrinfo *addr;
int rval, sock, opt_val;
rval = resolve_addr (argv[1], argv[2], AF_UNSPEC, &addr);
if ( rval != 0 ){
fprintf (stderr, "%s\n", gai_strerror (rval));
return 1;
}
sock = socket (addr->ai_family, addr->ai_socktype | SOCK_NONBLOCK, addr->ai_protocol);
if ( sock == -1 ){
fprintf (stderr, "error socket: %s\n", strerror (errno));
return 1;
}
opt_val = 1;
if ( setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &opt_val, sizeof (opt_val)) == -1 ){
fprintf (stderr, "error setsockopt: %s\n", strerror (errno));
return 1;
}
if ( bind (sock, (struct sockaddr*) addr->ai_addr, addr->ai_addrlen) == -1 ){
fprintf (stderr, "error bind: %s\n", strerror (errno));
return 1;
}
if ( listen (sock, 32) == -1 ){
fprintf (stderr, "error listen: %s\n", strerror (errno));
return 1;
}
sleep (120);
freeaddrinfo (addr);
close (sock);
return 0;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.