2015-04-20 2 views
1

Я хочу выйти из блокировки вызова recv(). Исходя из этого question, я должен сделать следующее:Выход из вызова recv() блокировки

shutdown(s, SD_RECEIVE); 

Но это не работает, recv() все еще блокирует!


Edit:

Это код, который я использовал:

#include <stdio.h> 
#include <WinSock2.h> 
#include <Windows.h> 
#include <process.h> 
#pragma comment(lib, "ws2_32.lib") 

unsigned int __stdcall recvThread(void *p) 
{ 
    SOCKET s = *((SOCKET*)p); 

    char buffer[2048]; 
    int size; 

    do 
    { 
     size = recv(s, buffer, 2048, 0); 

     if (size > 0)        
     { 
      printf("Some data received\n"); 
     } 
     else if (size == 0) 
     { 
      printf("Disconnected\n"); 
     } 
     else 
     { 
      printf("Disconnected, error occured\n"); 
     } 

    } while (size > 0); 

    return 0; 
} 

int main() 
{ 
    // Initialize Winsock 
    WSADATA wsa; 
    WSAStartup(MAKEWORD(2, 2), &wsa); 

    // Create socket 
    SOCKET s = socket(AF_INET, SOCK_STREAM, 0); 

    // Connect 
    sockaddr_in addr; 
    addr.sin_family = AF_INET; 
    addr.sin_addr.s_addr = inet_addr("192.168.1.4"); 
    addr.sin_port = htons(atoi("12345")); 
    if (connect(s, (sockaddr*)&addr, sizeof(addr)) == SOCKET_ERROR) 
    { 
     printf("Unable to connect\n"); 
    } 
    else 
    { 
     printf("Connected\n"); 
    } 

    // Start recv() thread 
    HANDLE hRecvThread = (HANDLE)_beginthreadex(0, 0, recvThread, &s, 0, 0); 

    Sleep(3000); 

    // Exit blocking recv() 
    shutdown(s, SD_RECEIVE); 

    getchar(); 
    return 0; 
} 
+0

Работы для всех остальных. 'Shutdown()' возвращает ошибку? Это было то же самое в обоих случаях? – EJP

+0

@EJP Нет, 'shutdown()' не возвратил ошибку. Да, это то же самое 's'. Обратите внимание, что я вызывал 'shutdown (s, SD_RECEIVE);' из другого потока (не из потока, который блокируется на 'recv()'). –

+0

Итак, чтобы быть понятным, 'shutdown (s, SD_RECEIVE)' возвращает ноль? Обратите внимание, что было бы невозможно вызвать его из * того же * потока, который блокировался на 'recv()'. – EJP

ответ

1

Вам нужно выключать вход, как упомянуто в вопросе вы связаны. Смотрите документацию для остановки() на MSDN и здесь, а также:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms738547%28v=vs.85%29.aspx

Соответствующие цитаты из документации:

Функция отключения используется на всех типах разъемов для отключения приема, передачи, или оба.
Если параметр SD_RECEIVE, последующие вызовы функции recv в сокете будут запрещены. Это не влияет на более низкие уровни протокола. Для сокетов TCP, если все еще есть данные в очереди, ожидающие получения, или данные поступают впоследствии, соединение сбрасывается, поскольку данные не могут быть доставлены пользователю. Для сокетов UDP входящие датаграммы принимаются и помещаются в очередь. Ни в коем случае не будет генерироваться пакет ошибок ICMP.
Если параметр SD_SEND, последующие вызовы функции отправки запрещены. Для сокетов TCP FIN будет отправлен после того, как все данные будут отправлены и подтверждены получателем.
Настройка SD_BOTH отключает как отправку, так и прием, как описано выше.

Ключ к отправке FIN. Это будет обрабатываться сервером, и он закроет сокет, что приведет к возврату вызова recv().

+0

Кто вам сказал, что «вход» означает «отправить»? –

+0

Он не работает, если сервер не принимает входные данные (клиент может слушать только), и в этом случае работает только 'closesocket'. – Liviu

+0

Поскольку «closesocket» на самом деле не рекомендуется («Клиент Winsock никогда не должен выпускать closesocket одновременно одновременно с другим вызовом функции Winsock».) Решение для такого типа сервера - это не блокирующий сокет ('select' +' recv'). – Liviu

Смежные вопросы