Загалом виявилось, що те про що я думав спочатку - неблокувальні сокети - це туфта. Що дійсно варто уваги, так це OVERLAPPED I/O. Тобто перетинний В/В, коли запити відбуваються асинхронно і час їх виконання перетинає один одного. Тут Microsoft дає можливість використовувати синхронізацію за допомогою WaitForSingle/MultipleObject(s). Що дуже зручно і я це й зробив із WSASend та WSARecv, але WSAConnect наразі не підтримує таку можливість, хоча і має зарезервований параметр для цього. Тому в наведеному коді використовується звичайний синхронний connect.
#include <WinSock2.h>
#include <Ws2tcpip.h>
#pragma comment(lib, "Ws2_32.lib")
#include <string>
#include <functional>
#include <memory>
#include <iostream>
using namespace std;
namespace
{
    int ResolveHostName(const char* hostname, struct in_addr* addr)
    {
        struct addrinfo *res;
        int result = getaddrinfo(hostname, NULL, NULL, &res);
        if (result == 0) {
            memcpy(addr, &((struct sockaddr_in *) res->ai_addr)->sin_addr,
                sizeof(struct in_addr));
            freeaddrinfo(res);
        }
        return result;
    }
    string GetWSALastErrorString(int errCode)
    {
        LPSTR errString;
        int size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM,
            0,
            errCode,
            0,
            (LPSTR)&errString,
            0,
            0);
        if (size != 0)
        {
            unique_ptr<CHAR, function<void(LPSTR)>> p(errString, [](LPSTR p) { LocalFree(p); });
            return p.get();
        }
        return "";
    }
}
int _tmain(int argc, _TCHAR* argv[])
{
    WSADATA wsaData;
    WSAStartup(MAKEWORD(2, 2), &wsaData);
    const string server = "ocw.mit.edu";
    //    const string server = "en.wikipedia.org";
    int port = 80;
    string httpGet = "GET http://ocw.mit.edu/courses/mechanical-engineering/2-003sc-engineering-dynamics-fall-2011/newton2019s-laws-vectors-and-reference-frames/MIT2_003SCF11_Pset1_sol.pdf HTTP/1.0\r\n"
        //    string httpGet = "GET http://en.wikipedia.org HTTP/1.0\r\n"
        "From: me@bigboss.com\r\n"
        "User-Agent: HTTPTool/1.0\r\n"
        "\r\n";
    struct sockaddr_in address;
    memset(&address, 0, sizeof(address));
    address.sin_family = AF_INET;
    address.sin_port = htons(port);
    if (ResolveHostName(server.c_str(), &(address.sin_addr)) != 0) {
        inet_pton(PF_INET, server.c_str(), &(address.sin_addr));
    }
    SOCKET sd = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
    WSAOVERLAPPED overlapped;
    overlapped.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
    int wsResult;
    if (SOCKET_ERROR == ::connect(sd, (struct sockaddr*)&address, sizeof(address)))
    {
        cout << "Can't establish connection: " << GetWSALastErrorString(WSAGetLastError());
        return 1;
    }
    DWORD wsFlags = 0;
    int wsError = 0;
    WSABUF wsaBufSend{ httpGet.length(), NULL };
    DWORD bytesSend = -1;
    {
        wsaBufSend.buf = new char[httpGet.length() + 1];
        strcpy_s(wsaBufSend.buf, httpGet.length() + 1, httpGet.c_str());
        wsResult = WSASend(sd, &wsaBufSend, 1, &bytesSend, 0, &overlapped, NULL);
        // TO BE CHECKED: We don't need to preserve this buffer till end of asynchronous I/O
        delete[] wsaBufSend.buf;
    }
    if (wsResult != 0)
    {
        if ((wsResult == SOCKET_ERROR) && (WSA_IO_PENDING != (wsError = WSAGetLastError())))
        {
            cout << "Send failed with error: " << GetWSALastErrorString(wsError) << endl;
            return 1;
        }
        if (WAIT_FAILED == WSAWaitForMultipleEvents(1, &overlapped.hEvent, TRUE, INFINITE, FALSE))
        {
            cout << "Wait failed with error: " << GetWSALastErrorString(WSAGetLastError()) << endl;
            return 1;
        }
        if (FALSE == WSAGetOverlappedResult(sd, &overlapped, &bytesSend, FALSE, &wsFlags))
        {
            cout << "Recv failed with error: " << GetWSALastErrorString(WSAGetLastError()) << endl;
            return 1;
        }
    }
    const int BUF_SIZE = 1024*1024;
    WSABUF wsaBufRecv{ BUF_SIZE, new char[BUF_SIZE] };
    DWORD bytesRead = -1;
    while (bytesRead != 0)
    {
        wsResult = WSARecv(sd, &wsaBufRecv, 1, &bytesRead, &wsFlags, &overlapped, NULL);
        if (wsResult != 0)
        {
            if ((wsResult == SOCKET_ERROR) && (WSA_IO_PENDING != (wsError = WSAGetLastError())))
            {
                cout << "Recv failed with error: " << GetWSALastErrorString(wsError) << endl;
                break;
            }
            if (WAIT_FAILED == WSAWaitForMultipleEvents(1, &overlapped.hEvent, TRUE, INFINITE, FALSE))
            {
                cout << "Wait failed with error: " << GetWSALastErrorString(WSAGetLastError()) << endl;
                break;
            }
            if (FALSE == WSAGetOverlappedResult(sd, &overlapped, &bytesRead, FALSE, &wsFlags))
            {
                cout << "Recv failed with error: " << GetWSALastErrorString(WSAGetLastError()) << endl;
                break;
            }
        }
        wsaBufRecv.buf[bytesRead] = 0;
        cout << wsaBufRecv.buf;
    }
    return 0;
}
Так обробка помилок після цих асинхронних викликів досить громіздка.