Как объединить RECV и getMessage в цикле (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
}

Я знаю, что потоки существуют, но я хочу избежать использования потоков. Я буду использовать поток, если это единственный путь.

Изменить: Использование неблокирующего сокета не является решением, потому что, если нет доступных данных и нет сообщения в очереди, то моя программа завершит работу.

2 ответа

Решение

Я бы, конечно, пошел с отдельным потоком для сети recv() и всей связанной проверки / анализа протокола, поэтому изолировал его от цикла обработки сообщений. Такая нить была бы достаточно переносимой. Поток будет генерировать экземпляры структуры 'command' (malloc) и запускать их в функции внешнего обработчика. В Windows этот обработчик будет загружать адрес структуры в lParam/hParam сообщения WM_APP и публиковать его в потоке GetMessage(), где он будет получен обычным способом, отправлен в обработчик, структура извлечена, выполнена и затем освобождена.

Такой дизайн может показаться слишком сложным (и использует страшные потоки), но гораздо проще тестировать, отлаживать, расширять и улучшать, чем втиснуть все в асинхронный цикл сообщений, который делает все. Иногда дополнительная нить действительно проще:)

Используйте сокет в асинхронном (не неблокирующем) режиме через 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 ... 
        }
}
Другие вопросы по тегам