Přihlásit se pomocí účtu Microsoft
Přihlaste se nebo si vytvořte účet.
Dobrý den,
Vyberte jiný účet.
Máte více účtů.
Zvolte účet, pomocí kterého se chcete přihlásit.

Shrnutí

Někdy musíte svým přijímačům posílat naléhavá data o OOB (out-of-band). Příjemci jsou všichni uživatelé nebo aplikace, které data získávají. Chcete, aby se tato data OOB zpracovala jako data s vyšší prioritou, než všechna běžná data, která byste mohli posílat. Pokud mají data OOB, která chcete odeslat, jeden bajt, můžete data OOB vyhledat pomocí funkce Vybrat . Ke čtení dat můžete použít funkci přijmout . V protokolu TCP (Transmission Control Protocol) je však blok dat OOB vždy jeden bajt. Proto když posíláte víc bajtových dat OOB, načte se jenom poslední bajt dat OOB. Zbývající data se považují za běžná data. V tomto článku se používá ukázkový kód k popisu odesílání více bajtových dat OOB pomocí rozhraní Microsoft Windows Socket (Winsock).

V TOMTO ÚKOLU

ÚVOD

Tento článek popisuje, jak odesílat data mimo pásmo s více bajty pomocí rozhraní Winsock. Ukázkové aplikace se vytvářejí v Microsoft Visual C++. Protože tento mechanismus OOB není přímo podporovaný na úrovni soketu systému Microsoft Windows, musíte tento mechanismus OOB implementovat na úrovni aplikace. Tohle neplatí data OOB. V této ukázkové aplikaci vytvoříte dva sokety na straně klienta, které jsou označovány také jako odesílatel, a odesílají data OOB a běžná data. Na straně serveru, označované také jako přijímač, se ke zpracování dat ve dvou vláknech používají dva sokety. Jeden podproces je pro data OOB. Druhé vlákno je pro běžná data. Chcete-li simulovat mechanismus OOB, musíte synchronizovat tyto dva podprocesy. Ujistěte se, že vlákno, které zpracovává data OOB, má vyšší prioritu než vlákno, které zpracovává běžná data.Poznámka Tato ukázková aplikace popisuje jeden způsob, jak odeslat vícebajtová data OOB. Možná budete muset kód upravit, aby kód fungoval ve vašem prostředí.zpátky na začátek

Vytvoření klientské aplikace

  1. Vytvořte klientskou aplikaci. Následující ukázkový kód v této klientské aplikaci popisuje vytvoření dvou soketů:

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

    Proměnná myOOBSocket se používá k posílání dat OOB. Proměnná myNormalSocket se používá k posílání běžných dat.

  2. Vzhledem k tomu, že data, která proměnná myOOBSocket odesílá, nejsou pravdivá data OOB, musíte mít způsob, jak server sdělit, jaký druh dat bude mít soket před zahájením odesílání dat. Následující ukázkový kód popisuje, jak odeslat počáteční znak, který serveru oznamuje, jaký druh dat bude odeslán. Pro data OOB použijte "U" a pro běžná data použijte "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. Následující ukázkový kód popisuje, jak nastavit, aby klientská aplikace sledovala vstup od uživatele. Klientská aplikace posílá velká písmena jako data OOB. Duplikovat každý vstupní znak pro vytvoření násobku bajtového řetězce

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

Zobrazte ukázkový kód klientské aplikace, MyClient. cpp zpátky na začátek

Vytvoření serverové aplikace

  1. Následující ukázkový kód na straně serveru popisuje, jak vytvořit soket naslouchací služby pro sledování portu použitého pro komunikaci:

    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. Následující ukázkový kód popisuje, jak volat funkci Accept , aby soket naslouchací služby čekal na pokus o příchozí připojení:

    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. Chcete-li simulovat mechanismus OOB, musíte synchronizovat tyto dva podprocesy. V této ukázkové aplikaci použijte k tomu globální objekt události . Na začátek souboru zadejte následující příkaz.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Vytvořte obslužnou rutinu OOB, která je spouštěna zvláštním vláknem. V tomto popisovači můžete pomocí funkce Select zjistit, kdy data přijde. Po příchodu dat postupujte takto:

    1. Voláním funkce ResetEvent nastavte objekt události hRecvEvent na nesignálný.

      ResetEvent(hRecvEvent);

      Tento blok je normální obslužná rutina dat, která se provádí v jiném vlákně.

    2. Pokud chcete přečíst data, zavolejte funkci RevC .

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Vzhledem k tomu, že může být odesláno více dat, než může vyrovnávací paměť uchovat, volejte znovu volání funkce přijmout společně s příznakem MSG_PEEK , abyste zjistili, jestli jsou nějaká data na drátě dostupná.

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

      Podle toho, jestli data nečekají na čtení, použijte některou z následujících metod:

      • Pokud nechcete číst žádná data, zavolejte funkci SetEvent , abyste nastavili zadaný objekt události na stav signalizace.

        SetEvent(hRecvEvent);

        Po této akci se může obnovit normální vlákno obslužných rutin dat. Normální vlákno obslužných rutin dat čeká před pokračováním normálního vlákna obslužné rutiny dat o objektu události hRecvEvent .

      • Pokud ještě nečekáte na čtení dat, volejte na funkci přijmout znovu a přečtěte si zbývající data. Pak znovu vyhledejte čekající data.

    Opakujte kroky 4a až 4C, dokud nepřečte všechna nevyřízená data.

  5. Vytvořte normální obslužnou rutinu dat. Tento popisovač se podobá obsluze dat OOB s výjimkou toho, že normální obslužná rutina dat volá funkci WaitForSingleObject , když normální obslužná rutina dat zjistí, že data přišla.

    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.

Zobrazte ukázkový kód serverové aplikace, server. cpp zpátky na začátek

Zobrazení ukázkového kódu klientské aplikace, MyClient. cpp

Poznámka Abyste mohli kód zkompilovat, musíte do souboru knihovny Winsock odkazovat 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;}

zpátky na začátek

Zobrazte ukázkový kód serverové aplikace Server. cpp

Poznámka Abyste mohli kód zkompilovat, musíte do souboru knihovny Winsock odkazovat 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;}

zpátky na začátek

Test ukázky

  1. Na příkazovém řádku zadejte Server. exe 4444 a spusťte tak server na portu 4444. serverová aplikace zobrazí následující zprávu a počká na klienty:

    Server je připravený!

  2. V jiném okně příkazového řádku zadejteMyClient IPAddress 4444 a spusťte klienta. Poznámka Zástupný symbol IPAddress je zástupný symbol pro IP adresu serveru.

  3. Server zobrazí zprávu podobnou této:

    Waiting.Waiting*..*Když dostanete předchozí zprávu, musíte do 10 sekund před pokračováním serveru napsat aBcDeFgHi .

Po přibližně 10 sekundách Server zobrazí následující informace:

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [Normal]: aaaaaaaaaa [normální]: cccccccccc [normální]: eeeeeeeeee [Normal]: gggggggggg [Normal]: iiiiiiiiiizpátky na začátek

Odkazy

Další informace najdete na následujících webech MSDN (Microsoft Developer Network):

Nezávislá data mimo pásmohttp://msdn2.Microsoft.com/en-us/library/ms740102.aspxfunkce Winsockhttp://msdn2.Microsoft.com/en-us/library/ms741394.aspxDalší informace najdete v následujícím článku znalostní báze Microsoft Knowledge Base:

331756 Funkce Ioctlsocket nemůže rozpoznat vložená data mimo pásmo.zpátky na začátek

Potřebujete další pomoc?

Chcete další možnosti?

Prozkoumejte výhody předplatného, projděte si školicí kurzy, zjistěte, jak zabezpečit své zařízení a mnohem více.

Komunity vám pomohou klást otázky a odpovídat na ně, poskytovat zpětnou vazbu a vyslechnout odborníky s bohatými znalostmi.

Byly tyto informace užitečné?

Jak jste spokojeni s kvalitou jazyka?
Co ovlivnilo váš názor?
Po stisknutí tlačítka pro odeslání se vaše zpětná vazba použije k vylepšování produktů a služeb Microsoftu. Váš správce IT bude moci tato data shromažďovat. Prohlášení o zásadách ochrany osobních údajů.

Děkujeme vám za zpětnou vazbu.

×