Domanda

Ehi ... ho creato un piccolo server di test tramite I / O e le porte di completamento Winsock. Posso connettersi e associare un handle di socket con la porta di completamento. Ma Io non so come passare data-strutture definite dall'utente nella filettatura wroker ...

Che Ive provato finora è stato il superamento di un utente-struttura come (ULONG_PTR)&structure as la chiave Completamento nell'associazione chiamata di CreateIoCompletionPort() Ma non ha funzionato.

Ora ho cercato di definire la mia sovrapposti ed impiegando CONTAINING_RECORD (), come descritto qui http://msdn.microsoft.com/en-us/magazine/cc302334.aspx e http://msdn.microsoft.com/en-us/magazine/bb985148.aspx .  Ma questo non funziona, anche. (Ho i valori Freaky per il contenuto di pHelper)

Quindi la mia domanda è: come faccio a passare i dati al thread lavoratore utilizzando WSARecv (), GetQueuedCompletionStatus () e il pacchetto completamento o l'OVERLAPPED-strucutre

?

EDIT:? Come posso trasmettere con successo "per-connection-dati" ... Sembra che ho avuto l'arte di farlo (come spiegato nei due link sopra) sbagliato <. / p>

Qui va il mio codice: (Sì, la sua brutta e il suo unico TEST-code)

struct helper
    {
        SOCKET m_sock;
        unsigned int m_key;
        OVERLAPPED over;
    };


///////

SOCKET newSock = INVALID_SOCKET;
    WSABUF wsabuffer;
    char cbuf[250];
    wsabuffer.buf = cbuf;
    wsabuffer.len = 250;
    DWORD flags, bytesrecvd;


    while(true)
    {
        newSock = accept(AcceptorSock, NULL, NULL);
        if(newSock == INVALID_SOCKET)
            ErrorAbort("could not accept a connection");

        //associate socket with the CP
        if(CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, 3,0) != hCompletionPort)
            ErrorAbort("Wrong port associated with the connection");
        else
            cout << "New Connection made and associated\n";

        helper* pHelper = new helper;
        pHelper->m_key = 3;
        pHelper->m_sock = newSock;
        memset(&(pHelper->over), 0, sizeof(OVERLAPPED));
        flags = 0;
        bytesrecvd = 0;

        if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, (OVERLAPPED*)pHelper, NULL) != 0)
        {
            if(WSAGetLastError() != WSA_IO_PENDING)
                ErrorAbort("WSARecv didnt work");
        }
    }

    //Cleanup
    CloseHandle(hCompletionPort);
    cin.get();
    return 0;
}

DWORD WINAPI ThreadProc(HANDLE h)
{
    DWORD dwNumberOfBytes = 0;
    OVERLAPPED* pOver = nullptr;
    helper* pHelper = nullptr;
    WSABUF RecvBuf;
    char cBuffer[250];
    RecvBuf.buf = cBuffer;
    RecvBuf.len = 250;
    DWORD dwRecvBytes = 0;
    DWORD dwFlags = 0;
    ULONG_PTR Key = 0;

    GetQueuedCompletionStatus(h, &dwNumberOfBytes, &Key, &pOver, INFINITE);

    //Extract helper
    pHelper = (helper*)CONTAINING_RECORD(pOver, helper, over);


    cout << "Received Overlapped item" << endl;
    if(WSARecv(pHelper->m_sock, &RecvBuf, 1, &dwRecvBytes, &dwFlags, pOver, NULL) != 0)
        cout << "Could not receive data\n";
    else
        cout << "Data Received: " << RecvBuf.buf << endl;

    ExitThread(0);
}
È stato utile?

Soluzione

È possibile inviare i dati per un fine particolare del proprio alla porta di completamento tramite PostQueuedCompletionStatus .

  

Il pacchetto di completamento O / I soddisferà   una chiamata eccezionale per la   Funzione GetQueuedCompletionStatus.   Questa funzione restituisce con i tre   valori passati come il secondo, terzo,   e il quarto parametro della chiamata a   PostQueuedCompletionStatus. Il sistema   non usa o convalidare questi valori.   In particolare, il lpOverlapped   parametro non deve puntare a un   struttura OVERLAPPED.

Altri suggerimenti

Se si passa lo struct come questo dovrebbe funzionare bene:

helper* pHelper = new helper;
CreateIoCompletionPort((HANDLE)newSock, hCompletionPort, (ULONG_PTR)pHelper,0);
...


helper* pHelper=NULL;
GetQueuedCompletionStatus(h, &dwNumberOfBytes, (PULONG_PTR)&pHelper, &pOver, INFINITE);

Modifica per aggiungere i dati per IO:

Una delle caratteristiche abusati spesso delle API asincrone è che non si copia lo struct OVERLAPPED, semplicemente utilizzare il previsto uno - da qui lo struct sovrapposta tornato da punti GetQueuedCompletionStatus alla struct originariamente previsto. Quindi:

struct helper {
  OVERLAPPED m_over;
  SOCKET     m_socket;
  UINT       m_key;
};

if(WSARecv(newSock, &wsabuffer, 1, NULL, &flags, &pHelper->m_over, NULL) != 0)

Si noti che, ancora una volta, nel campione originale, si stavano diventando il vostro sbagliato colata. (OVERLAPPED *) pHelper era passando un puntatore all'inizio della struct aiutante, ma la parte sovrapposta è stata dichiarata l'ultima. L'ho cambiato per passare l'indirizzo della parte reale sovrapposta, il che significa che il codice viene compilato senza un cast, che ci permette di conoscono stiamo facendo la cosa giusta. Ho anche spostato la struct sovrapposta di essere il primo membro della struct.

Per catturare i dati sul lato opposto:

OVERLAPPED* pOver;
ULONG_PTR key;
if(GetQueuedCompletionStatus(h,&dw,&key,&pOver,INFINITE))
{
  // c cast
  helper* pConnData = (helper*)pOver;

Su questo lato è particolarmente importante che la struct sovrapposta è il primo membro della struct aiutante, come che lo rende facile da indietro cast della OVERLAPPED * l'API ci dà, e l'aiutante * vogliamo davvero.

Io uso le routine di presa standard (socket, closesocket, si legano, accetta, connect ...) per la creazione / distruzione e ReadFile / WriteFile per I / O in quanto consentono l'uso della struttura OVERLAPPED.

Dopo la presa ha accettato o connessa si dovrebbe associarlo al contesto di sessione che i servizi. Poi si associa il socket a un IOCP e (nel terzo parametro) dotarla di un riferimento al contesto di sessione. L'IOCP non sa cosa questo riferimento è e non si cura né per quella materia. Il riferimento è per l'uso in modo che quando si ottiene un CIO attraverso GetQueuedCompletionStatus la variabile a cui punta il parametro 3 sarà riempito con il riferimento in modo da trovare subito contesto associato all'evento di presa e può iniziare la manutenzione della manifestazione. Uso solitamente una struttura indicizzata contenente (tra le altre cose) la dichiarazione presa, la struttura sovrapposta nonché altri dati di sessione-specifici. Il riferimento a passo CreateIoCompletionPort nel parametro 3 sarà l'indice all'elemento struttura contenente presa.

È necessario verificare se GetQueuedCompletionStatus restituito un completamento o un timeout. Con un timeout è possibile eseguire attraverso la struttura indicizzato e vedere (per esempio), se uno di loro è scaduta o qualcos'altro e adottare le opportune azioni house-keeping.

La struttura sovrapposta ha anche bisogno di essere controllato per vedere che l'I / O completata correttamente.

La funzione manutenzione del IOCP dovrebbe essere un'entità multi-thread separato. Utilizzare lo stesso numero di thread che avete core nel vostro sistema, o almeno non più di come sia spreca risorse di sistema (non si dispone di più risorse per la manutenzione l'evento rispetto al numero di core presenti nel sistema, giusto?) .

IOCPs sono davvero il migliore dei mondi (troppo bello per essere vero) e chi dice "un thread per ogni presa" o "attesa nella lista a più presa in una funzione" non sanno cosa stanno parlando. L'ex stress il programmatore e il secondo è di polling e sondaggi è sempre estremamente dispendioso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top