先决条件:
1、 创建IPV6套接字
2、打开套接字可重用
3、禁用仅限 IPV6
BOOL bEnable = FALSE;
if (setsockopt(listenfd_, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&bEnable), sizeof(bEnable)) < 0)
{
return false;
}
4、绑定套接字
5、使用 struct sockaddr_in6 结构接受套接字,而不是用缺省使用 “sockaddr”,否则 10014(WSAEFAULT)错误,并导致套接字句柄泄漏。
struct sockaddr_in6 address = { 0 };
int address_size = sizeof(address);
int sockfd = WSAAccept(listenfd_, (sockaddr*)&address, &address_size, NULL, NULL);
if (sockfd != INVALID_SOCKET)
{
AcceptSocketEventArgs e = { Adjust(sockfd) };
OnAcceptSocket(e);
}
完整大体代码为;
bool Open(const char* localIP, int localPort, int backlog) noexcept
{
if (localPort < IPEndPoint::MinPort || localPort > IPEndPoint::MaxPort)
{
return false;
}
if (NULL == localIP || *localIP == '\x0')
{
return false;
}
if (listenfd_ != INVALID_SOCKET)
{
return false;
}
if (NULL != hEvent_)
{
return false;
}
if (NULL != afo_)
{
return false;
}
if (NULL == context_)
{
return false;
}
boost::system::error_code ec;
boost::asio::ip::address bindIP = StringToAddress(localIP, ec);
if (ec)
{
return false;
}
if (backlog < 1)
{
backlog = PPP_LISTEN_BACKLOG;
}
in_ = bindIP.is_v4();
if (bindIP.is_v6())
{
struct sockaddr_in6 in6;
memset(&in6, 0, sizeof(in6));
in6.sin6_family = AF_INET6;
in6.sin6_port = htons(localPort);
if (inet_pton(AF_INET6, localIP, &in6.sin6_addr) < 1)
{
return false;
}
listenfd_ = WSASocket(AF_INET6, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (listenfd_ == INVALID_SOCKET)
{
return false;
}
Adjust(listenfd_);
if (!Socket::ReuseSocketAddress(listenfd_, true))
{
return false;
}
BOOL bEnable = FALSE;
if (setsockopt(listenfd_, IPPROTO_IPV6, IPV6_V6ONLY, reinterpret_cast<char*>(&bEnable), sizeof(bEnable)) < 0)
{
return false;
}
if (bind(listenfd_, reinterpret_cast<sockaddr*>(&in6), sizeof(in6)) < 0)
{
return false;
}
}
elif(bindIP.is_v4())
{
struct sockaddr_in in4;
memset(&in4, 0, sizeof(in4));
in4.sin_family = AF_INET;
in4.sin_port = htons(localPort);
if (inet_pton(AF_INET, localIP, &in4.sin_addr) < 1)
{
return false;
}
listenfd_ = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
if (listenfd_ == INVALID_SOCKET)
{
return false;
}
Adjust(listenfd_);
if (!Socket::ReuseSocketAddress(listenfd_, true))
{
return false;
}
if (bind(listenfd_, reinterpret_cast<sockaddr*>(&in4), sizeof(in4)) < 0)
{
return false;
}
}
else
{
return false;
}
if (listen(listenfd_, backlog) < 0)
{
return false;
}
hEvent_ = WSACreateEvent();
if (hEvent_ == WSA_INVALID_EVENT)
{
return false;
}
if (WSAEventSelect(listenfd_, hEvent_, FD_ACCEPT | FD_CLOSE) != NOERROR)
{
return false;
}
afo_ = make_shared_void_pointer<boost::asio::windows::object_handle>(*context_, hEvent_);
return Next();
}
接受套接字连入部分:
WSANETWORKEVENTS events;
if (WSAEnumNetworkEvents(listenfd, hEvent, &events) == NOERROR)
{
if (events.lNetworkEvents & FD_ACCEPT)
{
if (events.iErrorCode[FD_ACCEPT_BIT] == 0)
{
struct sockaddr_in6 address = { 0 };
int address_size = sizeof(address);
int sockfd = WSAAccept(listenfd_, (sockaddr*)&address, &address_size, NULL, NULL);
if (sockfd != INVALID_SOCKET)
{
AcceptSocketEventArgs e = { Adjust(sockfd) };
OnAcceptSocket(e);
}
}
}
elif(events.lNetworkEvents & FD_CLOSE)
{
if (events.iErrorCode[FD_ACCEPT_BIT] == 0) /* event is operation_canceled. */
{
return;
}
}
}