Riepilogo

A volte è necessario inviare dati urgenti fuori banda (OOB) ai destinatari. I destinatari sono tutti gli utenti o le applicazioni che ricevono i dati. Si desidera che i dati di OOB vengano trattati come dati con priorità più alta rispetto a qualsiasi dato normale che potrebbe essere inviato. Se i dati di OOB che si desidera inviare sono di un byte, è possibile usare la funzione Seleziona per cercare i dati di OOB. Per leggere i dati, è possibile usare la funzione ricevuti . In TCP (Transmission Control Protocol), tuttavia, il blocco di dati OOB è sempre un byte. Di conseguenza, se si inviano dati di OOB a più byte, viene recuperato solo l'ultimo byte dei dati di OOB. I dati rimanenti vengono trattati come dati normali. In questo articolo viene usato il codice di esempio per descrivere come inviare dati di OOB a più byte tramite Microsoft Windows Socket (Winsock).

CONTENUTO DELL'ATTIVITÀ

INTRODUZIONE

Questo articolo descrive come inviare dati fuori banda con più byte (caratteri) tramite Winsock. Le applicazioni di esempio vengono create in Microsoft Visual C++. Poiché questo meccanismo OOB non è supportato direttamente dal livello di socket di Microsoft Windows, è necessario implementare questo meccanismo di OOB a livello di applicazione. I dati di OOB non sono veri. In questa applicazione di esempio crei due socket sul lato client, noto anche come lato mittente, per inviare dati OOB e dati normali. Sul lato server, noto anche come lato ricevitore, si usano due socket per elaborare i dati in due thread. Un thread è per i dati di OOB. L'altro thread è per i dati normali. Per simulare il meccanismo OOB, è necessario sincronizzare questi due thread. Verificare che il thread che elabora i dati di OOB abbia una priorità maggiore rispetto al thread che elabora i dati normali.Nota Questa applicazione di esempio descrive un modo per inviare dati OOB a più byte. Potrebbe essere necessario rivedere il codice per far funzionare il codice nell'ambiente.torna all'inizio

Creare un'applicazione client

  1. Creare un'applicazione client. Nell'applicazione client, il codice di esempio seguente descrive come creare due socket:

    SOCKET myOOBSocket = INVALID_SOCKET;SOCKET myNormalSocket = INVALID_SOCKET;myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);

    La variabile myOOBSocket viene usata per inviare dati OOB. La variabile myNormalSocket viene usata per inviare dati normali.

  2. Dato che i dati inviati dalla variabile myOOBSocket non sono veri dati di OOB, è necessario disporre di un modo per indicare al server il tipo di dati che il socket deve inviare prima di iniziare a inviare dati. Il codice di esempio seguente descrive come inviare un carattere iniziale per informare il server sul tipo di dati che verranno inviati. USA "U" per i dati di OOB e USA "N" per i dati normali.

    int nErr, nSize;nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));//Look for a potential error here.//"remoteIp" is the remote address.nSize = send(myNormalSocket, "N",1, 0);//Look for a potential error here.nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));//Look for a potential error here.nSize = send(myOOBSocket,"U",1, 0);//Look for a potential error here.
  3. Il codice di esempio seguente descrive come fare in modo che l'applicazione client sorvegli l'input dell'utente. L'applicazione client invia caratteri maiuscoli come dati OOB. Duplicare ogni carattere di input per comporre una stringa a più byte.

    for (;;) {int ch = _getch();_putch( ch );if (ch=='.') {shutdown(myOOBSocket, 2);        shutdown(myNormalSocket,2);break;}        char buf[10];        memset(buf, ch, sizeof(buf));        if (isupper(ch)) {nSize = send(myOOBSocket, buf, sizeof(buf), 0);//Do not use the MSG_OOB flag. Send it as normal data.} else {nSize = send(myNormalSocket, buf, sizeof(buf), 0);}...}

Visualizzare il codice di esempio per l'applicazione client, client. cpp di nuovo all'inizio

Creare un'applicazione server

  1. Sul lato server, il codice di esempio seguente descrive come creare un socket listener per monitorare la porta usata per la comunicazione:

    int nErr;SOCKET myListener = INVALID_SOCKET;myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);//Look for a potential return error here.nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));//Look for a potential return error here.//"localIp" is the local address of the server.nErr = listen(myListener, 5);//Look for a potential return error here.
  2. Il codice di esempio seguente descrive come chiamare la funzione Accept per fare in modo che l'attesa del listener per la connessione in ingresso tenti:

    for (;;) {struct sockaddr_in remoteIp;SOCKET remoteSocket = INVALID_SOCKET;int nAddrLen = sizeof(SOCKADDR);remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);//"remoteIp" is a pointer to a buffer that receives //the address of the connecting entity.BYTE buffer[1+1];int recv_len=recv(remoteSocket,(char *)&buffer,1,0);//This supposes that the client sockets will send//"U" or "N" as the initial character.    buffer[recv_len] = '\0';if(strcmp((char *)buffer,"U")==0)hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);//Create a new thread to process incoming OOB data. "OOBHandler" is a //pointer to the OOB data handler. else if(strcmp((char *)buffer,"N")==0)hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);//Create a new thread to process incoming normal data. "NormalHandler" is //a pointer to the normal data handler....}
  3. Per simulare il meccanismo OOB, è necessario sincronizzare questi due thread. In questa applicazione di esempio, usa un oggetto evento globale per eseguire questa operazione. Inserire l'istruzione seguente nella parte superiore del file.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Crea il gestore OOB eseguito da un thread separato. In questo gestore si usa la funzione Seleziona per rilevare quando arrivano i dati. Quando i dati arrivano, eseguire le operazioni seguenti:

    1. Chiama la funzione ResetEvent per impostare l'oggetto evento hRecvEvent sullo stato non segnalato.

      ResetEvent(hRecvEvent);

      In questo blocco viene bloccato il gestore dati normale eseguito in un altro thread.

    2. Chiama la funzione revC per leggere i dati.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Poiché possono essere inviati più dati rispetto a quelli che il buffer può contenere, chiama di nuovo la funzione ricevuti , insieme al contrassegno MSG_PEEK , per determinare se i dati sono disponibili in rete.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);

      Usare uno dei metodi seguenti, a seconda che i dati in sospeso vengano letti o meno:

      • Se non ci sono dati in sospeso da leggere, chiama la funzione Separit per impostare l'oggetto evento specificato sullo stato segnalato.

        SetEvent(hRecvEvent);

        Quando si esegue questa operazione, il thread del gestore dati normale può riprendere. Il thread del gestore dati normale attende l'oggetto evento hRecvEvent prima che venga ripreso il thread del gestore dati normale.

      • Se i dati sono ancora in sospeso per la lettura, chiama di nuovo la funzione ricevuti per leggere i dati rimanenti. Esaminare quindi di nuovo i dati in sospeso.

    Ripetere i passaggi da 4a a 4C fino a quando tutti i dati in sospeso non sono stati letti.

  5. Creare il gestore dati normale. Questo gestore è simile al gestore dati OOB, con la differenza che il gestore dati normale chiama la funzione WaitForSingleObject quando il gestore dati normale rileva che i dati sono arrivati.

    WaitForSingleObject(hRecvEvent,INFINITE);//You can set the interval parameter to a specific value if you do not want  //the normal data handler to wait for the OOB handler indefinitely when OOB data arrives continuously.

Visualizzare il codice di esempio per l'applicazione server, myserver. cpp di nuovo all'inizio

Visualizzare il codice di esempio per l'applicazione client, client. cpp

Nota Per rendere il codice compilato, devi includere un riferimento al file della raccolta Winsock, Ws2_32. lib.

#include <stdio.h>#include <stdlib.h>#include <conio.h>#include <assert.h>#include <winsock.h>main(int argc, char *argv[]){int nErr, nSize;WSADATA wsaData;SOCKET myOOBSocket = INVALID_SOCKET;SOCKET myNormalSocket = INVALID_SOCKET;unsigned short nPort; // Listen for the port number.struct sockaddr_in remoteIp;if (argc!=3){printf("TcpDemoC <RemoteIp> <Port>\n");return 0;}// The Init Socket API.nErr = WSAStartup(MAKEWORD(1,1),&wsaData);assert(nErr==0);nPort = (unsigned short)atol(argv[2]);myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);assert(myOOBSocket!=INVALID_SOCKET);myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);assert(myNormalSocket!=INVALID_SOCKET);// Connect to the remote address.remoteIp.sin_family = AF_INET;remoteIp.sin_port = htons(nPort);;remoteIp.sin_addr.S_un.S_addr = inet_addr(argv[1]);nErr = connect(myOOBSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));if (nErr == SOCKET_ERROR) {printf("Connect failed because of %lX\n",  WSAGetLastError());goto Cleanup;}nSize = send(myOOBSocket,"U",1, 0);if (nSize == SOCKET_ERROR) {printf("Send failed because of %lX\n", WSAGetLastError());        goto Cleanup;}    nErr = connect(myNormalSocket, (SOCKADDR *)&remoteIp, sizeof(remoteIp));if (nErr == SOCKET_ERROR) {int error = WSAGetLastError();printf("Connect failed because of %lX\n", error);goto Cleanup;}    nSize = send(myNormalSocket, "N",1, 0);if (nSize == SOCKET_ERROR) {printf("Send failed because of %lX\n", WSAGetLastError());goto Cleanup;}printf("Read for input:\n");for (;;) {int ch = _getch();_putch( ch );if (ch=='.') {shutdown(myOOBSocket, 2);shutdown(myNormalSocket,2);break;}char buf[10];memset(buf, ch, sizeof(buf));if (isupper(ch)) {nSize = send(myOOBSocket, buf, sizeof(buf), 0);}else{nSize = send(myNormalSocket, buf, sizeof(buf), 0);}if (nSize == SOCKET_ERROR) {printf("Send failed because of %lX\n", WSAGetLastError());break;}}Sleep(1000);Cleanup:if (myOOBSocket!=INVALID_SOCKET)closesocket(myOOBSocket);if (myNormalSocket!=INVALID_SOCKET)closesocket(myNormalSocket);WSACleanup();return 0;}

torna all'inizio

Visualizzare il codice di esempio per l'applicazione server, myserver. cpp

Nota Per rendere il codice compilato, devi includere un riferimento al file della raccolta Winsock, Ws2_32. lib.

#include <windows.h>#include <stdio.h>#include <stdlib.h>#include <winsock.h>#include <assert.h>// Usage: myserver <port>HANDLE hRecvEvent; DWORD WINAPI OOBHandler(LPVOID lpParam){int nErr, nRecv_len;BYTE buffer[10 + 1];BOOL bClosing=FALSE;fd_set fdread;SOCKET remoteSocket=(SOCKET)lpParam;unsigned long ul=1;int nRet = ioctlsocket(remoteSocket, FIONBIO, &ul);if(SOCKET_ERROR==nRet){printf("Socket() failed: %d\n", WSAGetLastError());return 1;}printf("Waiting");for (int i=0; i<10; i++) {printf(".");Sleep(1000);}printf("The OOB handler is ready!\n");while (!bClosing){//Always clear the set before you call the select method.FD_ZERO(&fdread);//Add sockets to the sets.FD_SET(remoteSocket, &fdread);nErr=select(0,&fdread,0,0,0);if(nErr==SOCKET_ERROR){printf("Select() failed: %d\n",WSAGetLastError());return 1;}if(FD_ISSET(remoteSocket,&fdread)){ResetEvent(hRecvEvent);while(1){nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);                    if(nRecv_len==0){bClosing=TRUE;printf("The connection is closed!\n");break;}buffer[nRecv_len] = '\0';printf("[OOB]: %s\n", buffer);                    nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);if (nRecv_len==SOCKET_ERROR) {if(WSAGetLastError()==WSAEWOULDBLOCK)break;elseprintf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());}}SetEvent(hRecvEvent);} }return 0;}DWORD WINAPI NormalHandler(LPVOID lpParam){int nErr,nRecv_len;BYTE buffer[10 + 1];fd_set fdread;SOCKET remoteSocket=(SOCKET)lpParam;printf("Waiting");for (int i=0; i<10; i++) {        printf("*");Sleep(1000);}printf("Normal handler ready!\n");while(1) {//Always clear the set before you call the select method.FD_ZERO(&fdread);//Add sockets to the sets.FD_SET(remoteSocket, &fdread);nErr=select(0,&fdread,0,0,0);if(nErr==SOCKET_ERROR){printf("Select() failed: %d\n",WSAGetLastError());return 1;}if(FD_ISSET(remoteSocket,&fdread)){WaitForSingleObject(hRecvEvent,INFINITE);nRecv_len=recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);            if (nRecv_len==SOCKET_ERROR) {printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());return 1;}            if(nRecv_len==0){printf("Connection Closed!\n");break;}       buffer[nRecv_len] = '\0';printf("[Normal]: %s\n", buffer);}}return 0;}int main(int argc, char *argv[]){WSADATA wsaData;int nErr;SOCKET myListener = INVALID_SOCKET;struct sockaddr_in localIp;unsigned short nPort; DWORD dwThreadId;HANDLE hThread=NULL;if (argc!=2){printf("MyServer <Port>\n");return 0;}nPort = (unsigned short)atol(argv[1]);nErr = WSAStartup(MAKEWORD(2,0),&wsaData);assert(nErr==0);assert(wsaData.wVersion == MAKEWORD(2,0));myListener = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);assert(myListener!=INVALID_SOCKET);// Bind the listen socket to any local IP address.localIp.sin_family = AF_INET;localIp.sin_port = htons(nPort);;localIp.sin_addr.S_un.S_addr = INADDR_ANY;nErr = bind(myListener,(SOCKADDR *)&localIp,sizeof(localIp));assert(nErr!=SOCKET_ERROR);nErr = listen(myListener, 5);assert(nErr==0);//Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");if (hRecvEvent == NULL) { printf("CreateEvent failed with error 0x%lx\n", GetLastError());return 1;}printf("The server is ready!\n");for (;;) {struct sockaddr_in remoteIp;SOCKET remoteSocket = INVALID_SOCKET;int nAddrLen = sizeof(SOCKADDR);remoteSocket = accept(myListener, (SOCKADDR *)(&remoteIp), &nAddrLen);if(remoteSocket == INVALID_SOCKET) {int error = WSAGetLastError();printf("Accept() failed. Win32 error is 0x%lx\n", GetLastError());goto Cleanup;} else {printf("Connected from %d.%d.%d.%d:%d\n", remoteIp.sin_addr.S_un.S_un_b.s_b1,remoteIp.sin_addr.S_un.S_un_b.s_b2,remoteIp.sin_addr.S_un.S_un_b.s_b3,remoteIp.sin_addr.S_un.S_un_b.s_b4,ntohs(remoteIp.sin_port));BYTE buffer[1+1];int nRecv_len=recv(remoteSocket,(char *)&buffer,1,0);if (nRecv_len==SOCKET_ERROR) {printf("Recv() failed. Win32 error is 0x%lx\n", WSAGetLastError());return 1;}    buffer[nRecv_len] = '\0';if(strcmp((char *)buffer,"U")==0)hThread=CreateThread(0,0,OOBHandler,(LPVOID)remoteSocket, 0, &dwThreadId);else if(strcmp((char *)buffer,"N")==0)hThread=CreateThread(0,0,NormalHandler,(LPVOID)remoteSocket, 0, &dwThreadId);           if(hThread==0){printf("CreateThread() failed: %d\n",GetLastError());return 1;}CloseHandle(hThread);}}closesocket(myListener);Cleanup:WSACleanup();return 0;}

torna all'inizio

Testare l'esempio

  1. Al prompt dei comandi digitare MyServer. exe 4444 per avviare il server sulla porta 4444. l'applicazione server Visualizza il messaggio seguente e attende i client:

    Il server è pronto.

  2. In una finestra del prompt dei comandi diversa digitareclient IPAddress 4444 per avviare il client. Nota Il segnaposto IPAddress è un segnaposto per l'indirizzo IP del server.

  3. Il server Visualizza un messaggio simile al seguente:

    Waiting.Waiting*..*Quando si riceve il messaggio precedente, è necessario digitare aBcDeFgHi nel client entro 10 secondi prima che il server continui.

Dopo circa 10 secondi, il server Visualizza le operazioni seguenti:

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [normale]: Aladino [normale]: cccccccccc [normale]: eeeeeeeeee [normale]: gggggggggg [normale]: iiiiiiiiiitorna all'inizio

Riferimenti

Per altre informazioni, visitare i seguenti siti Web di Microsoft Developer Network (MSDN):

Funzioni Winsockhttp://msdn2.Microsoft.com/en-us/library/ms740102.aspxdi dati fuori banda indipendenti dal protocollohttp://msdn2.Microsoft.com/en-us/library/ms741394.aspxPer altre informazioni, fare clic sul numero dell'articolo della Microsoft Knowledge Base seguente per visualizzare l'articolo:

331756 La funzione ioctlsocket non riesce a rilevare i dati fuori banda inlineTorna all'inizio

Serve aiuto?

Amplia le tue competenze
Esplora i corsi di formazione
Ottieni in anticipo le nuove caratteristiche
Partecipa a Microsoft Insider

Queste informazioni sono risultate utili?

Come valuti la qualità della traduzione?
Cosa ha influito sulla tua esperienza?

Grazie per il feedback!

×