我是 IPV6 的新手,我需要将我的 IPV4 代码迁移到双栈。我有两个应用程序,一个支持 IPV6(双栈)并在服务器端使用,另一个基本上是仅 IPV4 的客户端。
请注意,在同一主机上,有一台服务器和多个客户端。由于设备支持双栈,一些封闭的应用程序只能使用 IPV4 来与我的服务器通信。因此,我正在尝试使用环回 IP。
当我在服务器端为“::1”地址创建套接字时,客户端无法使用“127.0.0.1”地址连接它。但是,当我在“::”地址上运行服务器时,客户端可以连接,而在服务器端,我将客户端 IP 视为 IPV4 映射地址 (::ffff.127.0.0.1)。但问题是,出于安全考虑,我需要在“::1”地址上运行服务器。
这是我在服务器端截取的代码;
struct addrinfo hints, *result, *rp;
int rc = 0;
int sck = -1;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
rc = getaddrinfo("::1", "9999", &hints, &result);
if (rc != 0) {
goto fail;
}
if (!result) {
goto fail;
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
sck = socket(rp->ai_family, rp->ai_socktype, 0);
if (sck == -1) {
continue;
}
int yes = 1;
if (setsockopt(sck, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int)) < 0) {
goto fail;
}
int v6OnlyEnabled = 0;
if (setsockopt(sck, IPPROTO_IPV6, IPV6_V6ONLY, &v6OnlyEnabled, sizeof(v6OnlyEnabled)) != 0) {
goto fail;
}
if (bind(sck, rp->ai_addr, rp->ai_addrlen) == 0) {
break; //Success
}
//Fail
close(sck);
sck = -1;
}
freeaddrinfo(result);
if (sck == -1) {
goto fail;
}
rc = listen(sck, 10);
if (rc < 0) {
//error
goto fail;
}
fail:
close(sck);
sck = -1;
这里是客户端;
struct addrinfo hints, *addr_list, *cur;
int retry = 0;
int sck = -1;
int rc = 0;
int val;
long arg;
struct pollfd pollfd;
socklen_t len = 0;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
rc = getaddrinfo("127.0.0.1", "9999", &hints, &addr_list);
if (rc != 0) {
printf("fail: %d\n", __LINE__);
goto fail;
}
for (cur = addr_list; (cur != NULL); cur = cur->ai_next) {
sck = socket(cur->ai_family, cur->ai_socktype, 0);
if (sck < 0) {
continue;
}
arg = fcntl(sck, F_GETFL, NULL);
arg |= O_NONBLOCK;
if (fcntl(sck, F_SETFL, arg) < 0) {
printf("fail: %d\n", __LINE__);
goto fail;
}
retry = 3;
while (--retry) {
//connecting
rc = connect(sck, cur->ai_addr, cur->ai_addrlen);
if (rc == 0) {
printf("OK: %d\n", __LINE__);
break;
}
pollfd.fd = sck;
pollfd.events = POLLIN | POLLOUT;
pollfd.revents = 0;
rc = poll(&pollfd, 1, 100000);
if (rc == 0) {
//timeout
printf("fail: %d\n", __LINE__);
close(sck);
sck = -1;
break;
}
len = sizeof(val);
rc = getsockopt(sck, SOL_SOCKET, SO_ERROR, (void *) (&val), &len);
if (rc < 0) {
//fail
printf("fail: %d\n", __LINE__);
close(sck);
sck = -1;
break;
}
if (val == EALREADY || val == EINPROGRESS) {
//connecting
printf("connecting: %d\n", __LINE__);
break;
}
if (val == ECONNREFUSED) {
(void)poll((void *)0, (unsigned long)0, (int)1000);
}
}
}
freeaddrinfo(addr_list);
if (sck < 0)
printf("fail %d\n", __LINE__);
fail:
close(sck);
sck = -1;
似乎禁用“IPV6_V6ONLY”选项不起作用。 另外,我已经比较了“proc/sys/net/ipv6/conf/lo”和“all”文件夹的内容。它们看起来一样(除了 use_tempaddr 和 mtu)
请帮我解决这个问题。
谢谢