我的应用程序需要在具有相同 IPv6 地址的同一端口上绑定(bind)一个套接字。我正在使用下面的代码来实现相同的目的。但是,第二次绑定(bind)会引发错误“地址已在使用中”。 顺便说一句,只有当我包含第一个套接字的监听调用时,我才会收到此错误。如果没有监听调用,第二个套接字就可以很好地绑定(bind)。
我做错了什么?请帮我理解。
谢谢
int fd1 = ::socket(AF_INET6, SOCK_STREAM, 0);
if (fd1 < 0)
{
perror("fd1 socket()");
return -1;
}
// Set SO_REUSEADDR for both sockets
int reuse = 1;
if (fcntl(fd1, F_SETFL, O_RDWR|O_NONBLOCK) <0)
{
perror("fd1 fcntl64 failed");
return -1;
}
if (::setsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("fd1 SO_REUSEADDR failed");
return -1;
}
if (::setsockopt(fd1, SOL_IPV6, IPV6_V6ONLY, &reuse, sizeof(reuse)) < 0)
{
perror("fd1 SO_REUSEADDR failed");
return -1;
}
sockaddr_storage storage;
socklen_t addrlen = sizeof(storage);
memset(&storage, 0, addrlen);
sockaddr_in6& addr = reinterpret_cast<sockaddr_in6&>(storage);
addr.sin6_family = AF_INET6;
addr.sin6_port = 143;
addr.sin6_addr = in6addr_any;
sockaddr* pAddr = reinterpret_cast<sockaddr*>(&storage);
int val = 2;
socklen_t len = sizeof(val);
if (::getsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &val, &len) < 0)
{
perror("fd1 getsock failed");
return -1;
}
printf("Getsockopt returned %d at %d\n",val, __LINE__);
if (::bind(fd1, pAddr, sizeof(sockaddr_in6)) < 0)
{
perror("bind fd1 failed");
return -1;
}
if (::getsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &val, &len) < 0)
{
perror("fd1 getsock failed");
return -1;
}
printf("Getsockopt returned %d at %d\n",val, __LINE__);
if (listen(fd1, 128) < 0)
{
perror("fd1, listen");
return -1;
}
if (::getsockopt(fd1, SOL_SOCKET, SO_REUSEADDR, &val, &len) < 0)
{
perror("fd1 getsock failed");
return -1;
}
printf("Getsockopt returned %d at %d\n",val, __LINE__);
// Get the local address for fd1
addrlen = sizeof(storage);
if (::getsockname(fd1, pAddr, &addrlen))
{
perror("getsockname for fd1 failed");
return -1;
}
char straddr[INET6_ADDRSTRLEN];
if (!inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr)))
{
perror("inet_ntop for fd1 failed");
return -1;
}
printf("fd1=%d addr=%s:%d\n", fd1, straddr, addr.sin6_port);
addrlen = sizeof(storage);
addr.sin6_family = AF_INET6;
addr.sin6_port = 143;
int fd2 = ::socket(AF_INET6, SOCK_STREAM, 0);
if (fd2 < 0)
{
perror("fd2 socket()");
return -1;
}
if (::setsockopt(fd2, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) < 0)
{
perror("fd2 SO_REUSEADDR failed");
return -1;
}
if (::setsockopt(fd2, SOL_IPV6, IPV6_V6ONLY, &reuse, sizeof(reuse)) < 0)
{
perror("fd1 SO_REUSEADDR failed");
return -1;
}
if (::bind(fd2, pAddr, sizeof(sockaddr_in6)) < 0)
{
perror("bind fd2 failed");
return -1;
}
// Get the local address for fd2
if (::getsockname(fd2, pAddr, &addrlen))
{
perror("getsockname for fd2 failed");
return -1;
}
if (!inet_ntop(AF_INET6, &addr.sin6_addr, straddr, sizeof(straddr)))
{
perror("inet_ntop for fd2 failed");
return -1;
}
printf("fd2=%d addr=%s:%d\n", fd2, straddr, addr.sin6_port);
return 0;
最佳答案
来自 socket(7)
手册页:
SO_REUSEADDR
- Indicates that the rules used in validating addresses supplied in abind(2)
call should allow reuse of local addresses. ForAF_INET
sockets this means that a socket may bind, except when there is an active listening socket bound to the address. When the listening socket is bound toINADDR_ANY
with a specific port then it is not possible to bind to this port for any local address. Argument is an integer boolean flag.
(强调我的)
您的第一个套接字绑定(bind)到相当于 INADDR_ANY
的 IPv6 上的端口 143,然后将其置于监听状态。因此,只要第一个套接字保持打开状态,就无法在端口 143 上绑定(bind)其他套接字。
关于c - 即使在 IPv6 中使用 SO_REUSEADDR 后,套接字绑定(bind)也会失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11684691/