我正在使用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);
如果我发送少量数据(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交互的,所以我没有得到“数据结束”吗?
最佳答案
如果WSARecv返回-1并且GetLastError不是WSA_IO_PENDING,则不会有异步完成。如果您想用一个额外的异步操作来处理这种情况,您可以用QueueUserAPC或postqueuedcomplementstatus自己安排它。
关于c - 处理WSARecv立即退回,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/47824583/