我正在使用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/

10-09 13:09