如何在循环中组合 RECV 和 getMessage(C、WINAPI)

How to combine RECV and getMessage in loop (C, WINAPI)

如何用 C 编写代码?

所需流量为:

Create socket
Create window
loop: Wait until data can be read from socket or message are added to the queue
if data then
  do stuff with data
  goto loop
else if message then
  do stuff with message
  goto loop

我试过这个代码:

MSG msg;
DWORD last=msg.time;
short bRet;
char command[20];
int n=0;
while((
       (n = recv(sock, command, sizeof command - 1, 0)) >= 0
       )||(
           (bRet = GetMessage( &msg, 0, 0, 0 )) != 0
           //I can't use peek message because it will have the same issue than non-blocking socket
           )){
    //here we check time of message if it is equal to last we know that is socket
}

我知道存在线程,但我想避免使用线程。如果这是唯一的方法,我会使用线程。

编辑: 使用非阻塞套接字不是解决方案,因为如果没有可用数据并且队列中没有消息,那么我的程序将退出。

通过WSAAsyncSelect()以异步(非非阻塞)模式使用套接字:

The WSAAsyncSelect function requests Windows message-based notification of network events for a socket.

套接字将通知指定的HWND套接字activity,如数据可用。

然后应用程序可以 运行 一个标准消息循环,在套接字消息从队列到达时处理它们。

#define WM_SOCKET_MSG (WM_APP + 1)

WSAAsyncSelect(sock, hwnd, WM_SOCKET_MSG, FD_READ | FD_WRITE | FD_CLOSE);

MSG msg;
char command[20];
int n;

while (GetMessage(&msg, 0, 0, 0)) {
        switch (msg.message) {
            case WM_SOCKET_MSG:
            {
                int event = WSAGETSELECTEVENT(msg.lParam);
                int error = WSAGETSELECTERROR(msg.lParam);
                if (error != 0) {
                    // process socket error as needed ...
                    break;
                }

                switch(event) {
                    case FD_READ:
                        n = recv(sock, command, sizeof command - 1, 0);
                        if (n > 0) {
                            // process data as needed ...
                        } else {
                            // process read error as needed ... 
                        }
                        break;
                    }

                    // process other socket events as needed ...
                }

                break;
            }

            // process other messages as needed ... 
        }
}

我肯定会为网络 recv() 和所有相关协议 checking/parsing 使用单独的线程,因此将其与消息处理循环隔离开来。这样的线程将是合理的可移植性。该线程将生成 'command' 结构实例 (malloc),并将它们触发到外部处理程序函数中。在 Windows 上,该处理程序会将结构地址加载到 WM_APP 消息的 lParam/hParam 中,并将其 post 加载到 GetMessage() 线程中,它将在通常情况下接收方式,分派给处理程序,提取结构,执行然后释放。

这样的设计可能会被视为过于复杂(并且使用可怕的线程),但它比将所有内容都塞进一个执行所有操作的异步消息循环更容易测试、调试、扩展和增强。有时,一个额外的线程确实更容易:)