我理解如果我通过文档建议的函数指针发出AcceptEx
调用,那么如果我指定了一个接收缓冲区大小,那么在发送一些数据之前调用将不会完成:
if (!lpfnAcceptEx(sockListen,
sockAccept,
PerIoData->Buffer,
DATA_BUFSIZE - ((sizeof(SOCKADDR_IN) + 16) * 2), /* receive buffer size */
sizeof(SOCKADDR_IN) + 16,
sizeof(SOCKADDR_IN) + 16,
&dwBytes,
&(PerIoData->Overlapped)
))
{
DWORD dwLastError = GetLastError();
// Handle error
}
来自MSDN
如果提供了接收缓冲区,则重叠操作不会 完成,直到接受连接并读取数据。使用 getsockopt函数与SO_CONNECT_TIME选项一起检查a 连接已被接受。
如果套接字未连接,则getsockopt返回0xFFFFFFFF。 检查重叠操作是否有的应用程序 完成后,结合SO_CONNECT_TIME选项即可 确定已接受连接但没有数据 接收。
建议通过关闭来终止此类连接 接受套接字,强制AcceptEx函数调用完成 有错误。
现在,这似乎表明我应该强行关闭套接字。但是,我的书" Microsoft Windows网络编程 - 第二版"陈述类似的事实,但接着说
作为警告,在任何情况下都不应该提出申请 关闭在没有的AcceptEx调用中使用的客户端套接字句柄 被接受,因为它可能导致内存泄漏。为了表现 原因,与AcceptEx调用相关的内核模式结构 关闭未连接的客户端句柄时不会清除 直到建立新的客户端连接或直到收听 套接字已关闭。
所以我不应该关闭它吗?我很困惑。
两个问题:
1)如果套接字尚未完全完成AcceptEx
,我会从getsockopt
返回0xFFFFFFFF。这使它成为永久关闭的候选人。但我怎么知道这个州坐了多久呢?我无法添加自己的时序逻辑,因为我不知道接受的时间是因为我的完成端口例程还没有完成!
2)当我弄清楚是否需要关闭套接字时,我该怎么做? closesocket()
足够吗?
答案 0 :(得分:1)
1)如果套接字尚未完全完成
AcceptEx
,我会回来 来自0xFFFFFFFF
的{{1}}。这使它成为强行的候选人 闭。
没有。这是错误的。如果你得到getsockopt
这意味着客户端不能连接套接字。它还在等待连接。我们需要停止这个操作,只有当我们决定停止监听端口时。否则我们不需要关闭此套接字或取消此i / o
但我怎么知道它坐了多久 州?我无法添加自己的时序逻辑,因为我不知道什么时候该 接受是因为我的完成端口例程还没有完成!
但是0xFFFFFFFF
getsockopt
并返回套接字已连接的秒数:
因此,如果此号码为SO_CONNECT_TIME
- 0xFFFFFFFF
仍在等待连接,则不得关闭/取消。否则(我们得到另一个值) - 这是客户端已经连接的秒数。看example of code
因此您可以定期检查套接字 - 如果您从AcceptEx
获得 N (!=-1
)秒 - 这意味着客户端已经 N 秒已连接到您的套接字但尚未发送任何数据。确切地说(当 N 变得太大时)使其成为强行关闭的候选者。但不是getsockopt( s, SOL_SOCKET, SO_CONNECT_TIME, (char *)&seconds, (PINT)&bytes)
值。
你理解错了。两篇文章之间没有矛盾:所以我现在不应该关闭它?我很困惑。
当未连接客户端句柄时,...将不会被清除 关闭......
请注意,此处说明在处理未连接状态时关闭使用-1 (0xFFFFFFFF)
的句柄。
建议这样( 已连接 但未收到任何数据) 通过关闭接受的套接字来终止连接
所以这里说关于已经已连接套接字。
所以你真的需要关闭已经连接的套接字,这里太长没有收到任何数据。套接字连接多久(以秒为单位) - 您通过AcceptEx
但是从我的选项中使用SO_CONNECT_TIME
中的接收缓冲区并不是一个好主意。客户端连接后更好的显式调用AcceptEx
。是的,这是对内核的额外调用。但另一方面,如果你在WSARecv
中使用接收缓冲区 - 你需要在每个侦听套接字上定期调用AcceptEx
(这是对内核的调用!)。因此,在getsockopt
已完成的套接字上调用一次 - 您需要在每个 T 时间段内对AcceptEx
进行 N 次调用。当客户端连接后getsockopt
完成时 - 您可以自己节省连接时间并自行定期检查此时间。但为此你不需要调用内核,这会更快。时间你可以通过AcceptEx
2)当我弄清楚是否需要关闭套接字时,我该怎么做?是
GetTickCount64
够了吗?
是closesocket()
需要且足够
答案 1 :(得分:0)
好的,我在查看Len Holgate在this link发布的代码后发现了这一点。
基本上我们需要存储所有SOCKET
个对象(我们创建它们以传递给我们获得的AcceptEx
函数指针,如上所示),以便迭代它们。 Microsoft Windows编程 - 第二版告诉我们,迭代挂起连接的好时机是我们有更多的连接想要被接受,而不是我们进行优秀的AcceptEx
调用。我们可以确定是否是这种情况:
WSAEVENT NewEvent = CreateEvent(0, FALSE, TRUE, 0); // Auto reset event
WSAEventSelect(sockListen, NewEvent, FD_ACCEPT);
if (::WaitForSingleObject(NewEvent, INFINITE) == WAIT_OBJECT_0)
// Need to post an AcceptEx
请注意使用自动重置事件,而不是WSACreateEvent()
创建的手动事件。现在,在发布AcceptEx
之后,我们可以遍历我们的待处理套接字,检查每个套接字的连接持续时间:
// Get the time for which this socket has been connected
::getsockopt(sock, SOL_SOCKET, SO_CONNECT_TIME, (char *)&nSeconds, &nBytes);
//
// If we decide the socket has been open for long enough, set SO_LINGER then close it
//
LINGER lingerStruct; // *
lingerStruct.l_onoff = 1; // Leave socket open...
lingerStruct.l_linger = 0; //...for 0 seconds after closesocket() is called
::setsockopt(sock, SOL_SOCKET, SO_LINGER, (char *)&lingerStruct, sizeof(lingerStruct));
closesocket(sock);
(*)请参阅here了解为何需要这样做。
最后一件事是从SOCKET
调用完成时保留的任何存储中移除AcceptEx
。