我正在编写一个 TCP 服务器(阻塞套接字模型)。当服务器等待(阻塞)接受新的连接尝试(我使用 WSAccept)时,我无法实现有效的正常程序退出。服务器监听套接字的代码是这样的(我省略了错误处理和其他不相关的代码):
int ErrCode = WSAStartup(MAKEWORD(2,2), &m_wsaData) ;
// Create a new socket to listen and accept new connection attempts
struct addrinfo hints, *res = NULL, *ptr = NULL ;
int rc, count = 0 ;
memset(&hints, 0, sizeof(hints)) ;
hints.ai_family = AF_UNSPEC ;
hints.ai_socktype = SOCK_STREAM ;
hints.ai_protocol = IPPROTO_TCP ;
hints.ai_flags = AI_PASSIVE ;
CString strPort ;
strPort.Format("%d", Port) ;
getaddrinfo(pLocalIp, strPort.GetBuffer(), &hints, &res) ;
strPort.ReleaseBuffer() ;
ptr = res ;
if ((m_Socket = WSASocket(res->ai_family, res->ai_socktype, res->ai_protocol, NULL, 0, 0)) == INVALID_SOCKET)
{
// some error
}
if(bind(m_Socket, (SOCKADDR *)res->ai_addr, res->ai_addrlen) == SOCKET_ERROR)
{
// some error
}
if (listen(m_Socket, SOMAXCONN) == SOCKET_ERROR)
{
// some error
}
到目前为止一切顺利......然后我在这样的线程中实现了 WSAccept 调用:
SOCKADDR_IN ClientAddr ;
int ClientAddrLen = sizeof(ClientAddr) ;
SOCKET TempS = WSAAccept(m_Socket, (SOCKADDR*) &ClientAddr, &ClientAddrLen, NULL, NULL);
当然,WSAccept 会阻塞,直到进行新的连接尝试,但是如果我想退出程序,那么我需要一些方法来让 WSAccept 退出。我尝试了几种不同的方法:
- 尝试从另一个线程中使用 m_Socket 调用 shutdown 和/或 closesocket 失败(程序只是挂起)。
- 使用 WSAEventSelect 确实解决了这个问题,但是 WSAccept 只提供非阻塞套接字——这不是我的意图。(有没有办法让套接字阻塞?)
- 我阅读了 APC 并尝试使用 QueueUserAPC(MyAPCProc, m_hThread, 1)) 之类的东西,但它也不起作用。
我究竟做错了什么 ?有没有更好的方法让这个阻塞 WSAccept 退出?