1

你如何在 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
}

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

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

4

2 回答 2

4

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

WSAAsyncSelect 函数为套接字请求基于 Windows 消息的网络事件通知。

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

然后,应用程序可以运行标准消息循环,在套接字消息从队列中到达时对其进行处理。

#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 ... 
        }
}
于 2017-07-19T17:12:08.753 回答
1

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

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

于 2017-07-19T17:44:36.177 回答