我正在使用WSARecv
实现异步服务器。根据文档,WSARecv可以立即返回0
。这仍然最终调用我的完成例程,我再次调用WSARecv
来获取其余数据。如果没有更多要抓取的数据,我预计随后对WSARecv
的调用将导致其完成例程在第二个参数中接收0
个字节。
所以,我打电话给接收:
// ret is zero after this call.
int ret = WSARecv(socket, buf, 1, &RecvBytes, &Flags, overlapped, WorkerRoutine);
最终,这会调用我的完成例程WorkerRoutine
,我会对数据进行一些处理,并最终再次调用WSARecv
以获取数据的其余部分。
void CALLBACK WorkerRoutine(DWORD recv_error, DWORD bytes, LPWSAOVERLAPPED overlapped, DWORD recv_flags)
{
int ret = 0;
const char* error = 0;
DWORD num_bytes = 0;
DWORD flags = 0;
if (recv_error != 0) {
goto cleanup;
}
// This is non-zero on the first call to the completion routine.
if (bytes == 0) {
return;
}
//... Omitted some data handling code.
WSABUF buf;
buf.buf = buffer;
buf.len = buff_size;
SecureZeroMemory(overlapped, sizeof(WSAOVERLAPPED));
// ret is -1 here and WSAGetLastError() == WSA_IO_PENDING
ret = WSARecv(sock, &buf, 1, &num_bytes, &flags, overlapped, WorkerRoutine);
如果我发送少量数据(< buff_size,例如'你好'),第一次调用WSARecv
将立即返回。仍然会调用完成例程,但我不会干净地退出完成例程,并发出另一个WSARecv
。我假设第二个完成例程最终会被调用,我可以检查bytes
是否为零,如果是{则不退出(不发出对WSARecv
的另一个调用)。相反,永远不会执行第二个完成例程。
这是对完成例程如何工作的误解吗?忽略第二个完成例程永远不会触发的事实是否安全?
为了完整起见,我使用Python脚本与我的服务器进行交互:
import socket
import sys
import time
HOST, PORT = "localhost", 9999
data = " ".join(sys.argv[1:])
# Create a socket (SOCK_STREAM means a TCP socket)
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try:
# Connect to server and send data
sock.connect((HOST, PORT))
sock.sendall(data + "\n")
# Receive data from the server and shut down
received = sock.recv(1024)
finally:
sock.close()
print "Sent: {}".format(data)
print "Received: {}".format(received)
我没有得到"数据结束"因为我是如何与Python互动的?
答案 0 :(得分:0)
如果WSARecv返回-1并且GetLastError不是WSA_IO_PENDING,则不会出现异步完成。如果您想通过额外的异步操作来处理这种情况,可以使用QueueUserAPC或PostQueuedCompletionStatus自行安排。