Aanmelden met Microsoft
Meld u aan of maak een account.
Hallo,
Selecteer een ander account.
U hebt meerdere accounts
Kies het account waarmee u zich wilt aanmelden.

Samenvatting

Soms moet u urgente gegevens (OOB) verzenden naar uw ontvangers. Ontvangers zijn gebruikers of toepassingen die de gegevens ontvangen. U wilt deze OOB-gegevens behandelen als gegevens met een hogere prioriteit dan de gegevens die u kunt verzenden. Als de OOB-gegevens die u wilt verzenden één byte zijn, kunt u de functie Select gebruiken om te zoeken naar OOB-gegevens. U kunt de functie recv gebruiken om de gegevens te lezen. In TCP (Transmission Control Protocol) heeft het OOB-gegevensblok echter altijd één byte. Als u echter meerdere byte OOB-gegevens verzendt, worden alleen de laatste byte van de OOB-gegevens opgehaald. De resterende gegevens worden behandeld als normale gegevens. In dit artikel wordt gebruikgemaakt van voorbeeldcode voor het verzenden van meerdere byte OOB-gegevens met behulp van Microsoft Windows Socket (Winsock).

IN DEZE TAAK

Inleiding

In dit artikel wordt beschreven hoe u met Winsock meerdere bytes (tekens) kunt verzenden met behulp van Winsock. De voorbeeldtoepassingen worden gemaakt in Microsoft Visual C++. Aangezien dit OOB-mechanisme niet rechtstreeks wordt ondersteund op het niveau van Microsoft Windows Socket, moet u dit OOB-mechanisme op het niveau van de toepassing implementeren. Dit geldt niet voor OOB-gegevens. In deze voorbeeldtoepassing maakt u twee sockets op de clientkant, ook wel bekend als de afzender, om OOB-gegevens en normale gegevens te verzenden. Aan de kant van de server, ook wel bekend als de ontvanger, gebruikt u twee sockets om de gegevens in twee threads te verwerken. Eén thread is voor OOB-gegevens. De andere thread is bedoeld voor normale gegevens. Als u het OOB-mechanisme wilt simuleren, moet u deze twee threads synchroniseren. Zorg ervoor dat de thread die OOB-gegevens verwerkt, een hogere prioriteit heeft dan de thread waarmee normaal gegevens worden verwerkt.Opmerking In deze voorbeeldtoepassing wordt één manier beschreven voor het verzenden van gegevens van meerdere bytes OOB. Het kan zijn dat u de code moet wijzigen om de code in uw omgeving te laten werken.terug naar begin

Een clienttoepassing maken

  1. Maak een clienttoepassing. In deze clienttoepassing wordt de volgende voorbeeldcode beschreven voor het maken van twee sockets:

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

    De variabele myOOBSocket wordt gebruikt voor het verzenden van OOB-gegevens. De variabele myNormalSocket wordt gebruikt voor het verzenden van normale gegevens.

  2. Aangezien de gegevens die de myOOBSocket -variabele verzendt, geen echt OOB-gegevens zijn, moet u op een manier te informeren over welke gegevens de socket moet verzenden voordat u gegevens gaat verzenden. Met de volgende voorbeeldcode wordt beschreven hoe u een eerste teken kunt verzenden om de server op de hoogte te stellen van de typen gegevens die worden verzonden. Gebruik ' U ' voor OOB-gegevens en gebruik ' N ' voor normale gegevens.

    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. Met de volgende voorbeeldcode wordt beschreven hoe u de invoer van de clienttoepassing controleert voor de gebruiker. De clienttoepassing verzendt tekens met hoofdletters als OOB-gegevens. Dupliceer elk invoerteken om een tekenreeks met meerdere bytes op te stellen.

    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);}...}

De voorbeeldcode voor de clienttoepassing Myclient. cpp weergeven aan de bovenkant

Een servertoepassing maken

  1. Aan de hand van de volgende voorbeeldcode wordt beschreven hoe u een listener-socket maakt voor het bewaken van de poort die wordt gebruikt voor communicatie:

    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. Met de volgende voorbeeldcode wordt beschreven hoe u de functie accepteren aanroept om te zorgen dat de listener-socket wacht op binnenkomende verbindingspogingen:

    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. Als u het OOB-mechanisme wilt simuleren, moet u deze twee threads synchroniseren. Gebruik in dit voorbeeldtoepassing een globaal gebeurtenis object om dit te doen. Zet de volgende instructie boven aan het bestand.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Maak de OOB-handler die wordt uitgevoerd door een afzonderlijke thread. In deze handler gebruikt u de functie Select om te bepalen wanneer gegevens binnenkomen. Voer de volgende stappen uit wanneer u gegevens ontvangt:

    1. Bel de functie ResetEvent om het hRecvEvent -gebeurtenisobject in te stellen op de niet-gesignaleerde status.

      ResetEvent(hRecvEvent);

      Dit blokkeert de Normal. data-handler die wordt uitgevoerd in een andere thread.

    2. Bel de revc -functie om de gegevens te lezen.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Aangezien er meer gegevens kunnen worden verzonden dan de buffer kan bevatten, kunt u de functie recv opnieuw aanroepen, samen met de MSG_PEEK vlag, om te bepalen of er gegevens op het netwerk beschikbaar zijn.

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

      Voer een van de volgende methoden uit, afhankelijk van of de gegevens in behandeling zijn om te worden gelezen of niet.

      • Als er geen gegevens in behandeling zijn om te worden gelezen, roept u de functie SetEvent om het opgegeven gebeurtenisobject in te stellen op de signaal status.

        SetEvent(hRecvEvent);

        Wanneer u dit doet, kan de thread voor de normale gegevensthreading worden hervat. De thread voor de normale gegevensthreading wacht op het hRecvEvent -gebeurtenisobject voordat de Normal data handler-thread wordt hervat.

      • Als er nog steeds niet in behandeling zijn om te worden gelezen, roept u nogmaals de functie recv aan om de resterende gegevens te lezen. Kijk vervolgens opnieuw naar gegevens die in behandeling zijn.

    Herhaal de stappen 4 tot en met 4c totdat alle in behandeling zijnde gegevens zijn gelezen.

  5. Maak de Normal. data-handler. Deze handler is vergelijkbaar met de optie voor OOB-gegevens, met uitzondering van de enige detectie van de normale gegevens

    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.

De voorbeeldcode voor de servertoepassing, mijnserver. cpp weergeven op de bovenkant

De voorbeeldcode voor de clienttoepassing Myclient. cpp weergeven

Opmerking U moet een verwijzing naar het bestand met de Winsock-bibliotheek Ws2_32. lib opnemen om de compilatie van de code mogelijk te maken.

#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;}

terug naar begin

De voorbeeldcode voor de servertoepassing, mijnserver. cpp weergeven

Opmerking U moet een verwijzing naar het bestand met de Winsock-bibliotheek Ws2_32. lib opnemen om de compilatie van de code mogelijk te maken.

#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;}

terug naar begin

Een steekproef testen

  1. Typ op de opdrachtprompt server . exe 4444 om de server te starten op Port 4444. de servertoepassing wordt het volgende bericht weergegeven en wacht op clients:

    De server is klaar.

  2. Typ in een ander venster van de opdracht promptMyClient IPAddress 4444 om de client te starten. Opmerking De tijdelijke aanduiding IPAddress is een tijdelijke aanduiding voor het IP-adres van de server.

  3. Op de server wordt een bericht weergegeven dat er ongeveer als volgt uitziet:

    Waiting.Waiting*..*Wanneer u het vorige bericht ontvangt, moet u binnen 10 seconden aBcDeFgHi op de clienttypen.

Na 10 seconden geeft de server het volgende:

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: waarde ffffffffff GECONVERTEERD [OOB]: HHHHHHHHHH [Normal]: AAAAAAAAAA [Normal]: cccccccccc [Normal]: Eeeeeeeeee [Normal]: gggggggggg [Normal]: iiiiiiiiiiterug naar boven

Verwijzingen

Ga naar de volgende websites van MSDN (Microsoft Developer Network) voor meer informatie:

Protocol-onafhankelijk uit de band datahttp://msdn2.Microsoft.com/en-us/library/ms740102.aspxWinsock-functieshttp://msdn2.Microsoft.com/en-us/library/ms741394.aspxKlik op het volgende artikelnummer in de Microsoft Knowledge Base voor meer informatie:

331756 De functie Ioctlsocket kan niet in line niet-gestreepte gegevens detecterenterug naar boven

Meer hulp nodig?

Uw vaardigheden uitbreiden

TRAINING VERKENNEN >

Als eerste nieuwe functies krijgen

DEELNEMEN AAN MICROSOFT 365 INSIDERS >

Was deze informatie nuttig?

Hoe tevreden bent u met de taalkwaliteit?
Wat heeft uw ervaring beïnvloed?

Hartelijk dank voor uw feedback.

×