Logige sisse Microsofti kontoga
Logige sisse või looge konto.
Tere!
Valige mõni muu konto.
Teil on mitu kontot
Valige konto, millega soovite sisse logida.

Kokkuvõte

Mõnikord peate saatma oma vastuvõtjatele kiiresti välja-of-Band (OOB) andmed. Vastuvõtjad on kõik kasutajad või andmed saanud rakendused. Soovite, et OOB andmed oleksid kõrgemad kui tavalised andmed, mida võite saata. Kui OOB andmed, mida soovite saata, on ühe baidi, saate OOB andmete otsimiseks kasutada funktsiooni Select . Andmete lugemiseks saate kasutada funktsiooni Võta vastu . Kuid edastuse protokollis (TCP) on OOB alati 1 bait. Seega, kui saadate mitu baidist OOB, laaditakse alla ainult OOB andmete Viimane bait. Ülejäänud andmeid käsitletakse nagu tavalisi andmeid. See artikkel kasutab proovi koodi, et kirjeldada, kuidas saata Microsoft Windowsi sokli (Winsocki) abil mitme baidiga OOB andmeid.

ARTIKLI TEEMAD

SISSEJUHATUS

Selles artiklis kirjeldatakse, kuidas saata Winsock-i abil mitu baiti (tähemärki) out-of-Band andmeid. Valimi rakendused luuakse rakenduses Microsoft Visual C++. Kuna see OOB mehhanism pole Microsoft Windowsi sokli tasemel otseselt toetatud, peate rakendama selle OOB mehhanismi rakenduse tasemel. See ei ole tõene OOB andmed. Selle proovi rakenduses loote kaks sokli klienti, mida tuntakse ka saatja poole, et saata OOB andmeid ja tavalisi andmeid. Serveri poolel, mida tuntakse ka vastuvõtja poole, saate andmete töötlemiseks kahes jutulõngas kasutada kahte pistikupesad. OOB andmete jaoks on tegemist ühe lõimega. Teine lõim on tavaliste andmete jaoks. OOB mehhanismi simuleerimiseks peate need kaks lõime sünkroonima. Veenduge, et andmete OOB töötlev lõim oleks kõrgem kui tavaline andmeid töötlev lõim.Märkus. Selles näites kirjeldatakse ühte viisi mitme baidise OOB andmete saatmiseks. Võimalik, et peate koodi muutma, et kood töötaks teie keskkonnas.tagasi algusse

Klientrakenduse loomine

  1. Looge klientrakendus. Selles klientarvutis on järgmises näites kood, mis kirjeldab kahe sokli loomist.

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

    MyOOBSocket muutujat kasutatakse OOB andmete saatmiseks. MyNormalSocket muutujat kasutatakse tavaliste andmete saatmiseks.

  2. Kuna myOOBSocket muutujaga saadetud andmed pole tõesed OOB andmed, peab teil olema viis anda serverile teada, millist tüüpi andmeid peaks pistikupesa enne andmete saatmise alustamist saatma. Järgmine proovi kood kirjeldab, kuidas saata algset märki, et teatada serverile saadetavate andmete kohta. Kasuta OOB andmete jaoks "U" ja kasuta tavalisi andmeid "N".

    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. Järgmine proovi kood kirjeldab, kuidas muuta klientrakendus kasutaja sisestatud sisendi jälgimiseks. Klientrakendus saadab suurtähed OOB andmetena. Mitme baidiga stringi koostamiseks dubleerige iga sisendi märk.

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

Kuvage klientrakenduse valimi kood, myclient. cpp tagasi algusse

Serveri rakenduse loomine

  1. Serveri poolel on järgmine proovi kood, mis kirjeldab, kuidas luua kuulaja pesa, mida kasutatakse suhtlemiseks kasutatava pordi jälgimiseks.

    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. Järgmine proovi kood kirjeldab, kuidas helistada funktsiooni Accept (kuulaja socket), et oodata sissetulevat ühendust.

    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. OOB mehhanismi simuleerimiseks peate need kaks lõime sünkroonima. Selle proovi rakenduses kasutage selleks globaalse sündmuse objekti. Asetage järgmine avaldus selle algusesse.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Saate luua OOB ohjuri, mille teostab eraldi lõim. Selles ohjuris saate andmete saabumise tuvastamiseks kasutada funktsiooni Select . Andmete saabumisel tehke järgmist.

    1. Helistage funktsiooni ResetEvent abil, et määrata hRecvEvent sündmuse objekt mitte-signaalitud olekusse.

      ResetEvent(hRecvEvent);

      See blokeerib tavalise andmete käitleja, mis käivitatakse mõnes muus jutulõngas.

    2. Andmete lugemiseks helistage funktsiooni revc .

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Kuna puhvri mahust võib rohkem andmeid saata, helistage uuesti funktsiooni Võta vastu koos MSG_PEEK lipuga, et teha kindlaks, kas andmed on saadaval ka juhtmel.

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

      Kasutage ühte järgmistest meetoditest, olenevalt sellest, kas andmed on loetud või mitte.

      • Kui andmeid ei saa lugeda, helistage funktsiooni SetEvent , et määrata määratud sündmuse objekt signaalitud olekusse.

        SetEvent(hRecvEvent);

        Kui seda teete, saab tavaline andmete ohjuri lõim jätkata. Tavaline andmete ohjuri lõim ootab hRecvEvent sündmuse objekti enne, kui tavaline andmete käitleja lõim uuesti algab.

      • Kui andmeid ei saa veel lugeda, helistage ülejäänud andmete lugemiseks uuesti funktsiooni Võta vastu . Seejärel vaadake uuesti pooleliolevad andmed.

    Korrake juhiseid 4a kuni 4c, kuni kõik ootel olevad andmed on loetud.

  5. Looge tavaline andmete käitleja. See ohjur sarnaneb OOB, välja arvatud juhul, kui tavaline andmete käitleja helistab funktsiooni WaitForSingleObject , kui tavaline andmete käitleja tuvastab, et andmed on saabunud.

    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.

Kuvage serveri rakenduse proovi kood, minuserver. cpp tagasi algusse

Saate kuvada klientrakenduse näidise koodi, myclient. cpp

Märkus. Koodi kompileerimiseks tuleb lisada viide Winsocki teegi failile 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;}

tagasi algusse

Serveri rakenduse proovi koodi kuvamine, minuserver. cpp

Märkus. Koodi kompileerimiseks tuleb lisada viide Winsocki teegi failile 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;}

tagasi algusse

Proovi test

  1. Tippige käsureale minuserver. exe 4444 , et käivitada server pordi 4444. serveri rakendus kuvab järgmise teate ja ootab kliente.

    Server on valmis!

  2. Tippige mõne muu käsuviiba aknasseMyClient sordib 4444 , et käivitada klient. Märkus. Kohatäite sordib on serveri IP-aadressi kohatäide.

  3. Server kuvab teate, mis sarnaneb järgmisega:

    Waiting.Waiting*..*Kui saate eelmise sõnumi, peate tippima aBcDeFgHi klienti 10 sekundi jooksul enne serveri jätkamist.

Pärast umbes 10 sekundit kuvatakse serveris järgmine teave.

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [normaalne]: aaaaaaaaaa [normaalne]: cccccccccc [normaalne]: eeeeeeeeee [normaalne]: gggggggggg [tavaline]: iiiiiiiiiitagasi algusse

Viited

Lisateabe saamiseks külastage järgmisi Microsoft Developer Networki (MSDN-i) veebisaite.

Protokoll – sõltumatu out-of-Band andmetehttp://msdn2.microsoft.com/en-us/Library/ms740102.aspxwinsocki funktsioonidehttp://msdn2.microsoft.com/en-us/Library/ms741394.aspxLisateabe saamiseks klõpsake Microsofti teabebaasi (Knowledge Base) artikli kuvamiseks järgmist artiklinumbrit:

331756 Funktsioon Ioctlsocket ei suuda tuvastada tekstisiseseid andmeid.tagasi algusse

Kas vajate veel abi?

Kas soovite rohkem valikuvariante?

Siin saate tutvuda tellimusega kaasnevate eelistega, sirvida koolituskursusi, õppida seadet kaitsma ja teha veel palju muud.

Kogukonnad aitavad teil küsimusi esitada ja neile vastuseid saada, anda tagasisidet ja saada nõu rikkalike teadmistega asjatundjatelt.

Kas sellest teabest oli abi?

Kui rahul te keelekvaliteediga olete?
Mis mõjutas teie hinnangut?
Kui klõpsate nuppu Edasta, kasutatakse teie tagasisidet Microsofti toodete ja teenuste täiustamiseks. IT-administraator saab neid andmeid koguda. Privaatsusavaldus.

Täname tagasiside eest!

×