Prijavite se pomoću Microsofta
Prijavi se ili izradi račun.
Zdravo,
Odaberite drugi račun.
Imate više računa
Odaberite račun putem kojeg se želite prijaviti.

Sažetak

Ponekad morate u prijemnike morati uputiti hitnu (OOB) podatke iz grupe. Primatelji su svi korisnici ili aplikacije koje primaju podatke. Želite da se ovaj OOB podaci tretiraju kao podaci viših prioriteta nego bilo koje normalne podatke koje šaljete. Ako su podaci o OOB-u koje želite uputiti jedan byte, možete koristiti funkciju Select da biste potražili podatke o OOB-u. Možete koristiti funkciju primaj da biste pročitali podatke. No u protokolu za upravljanje prijenosom (TCP) okvir OOB podataka uvijek je jedan byte. Dakle, ako šaljete više-byte OOB podatke, dohvaćaju se samo posljednji byte podataka OOB. Preostali se podaci tretiraju kao normalni podaci. U ovom se članku koristi ogledni kod da bi se opisao način slanja podataka o OOB-u s više bajta pomoću sustava Microsoft Windows Socket (Winsock).

U OVOM ZADATKU

UVOD

U ovom se članku opisuje način slanja podataka iz više bajtova (chars-a) pomoću značajke Winsock. Ogledne aplikacije stvaraju se u programu Microsoft Visual C++. Budući da ovaj mehanizam OOB nije izravno podržan na razini utičnice sustava Microsoft Windows, morate implementirati ovaj mehanizam OOB na razini aplikacije. To nije istina OOB podatke. U ovoj oglednoj aplikaciji stvarate dvije utičnice na strani klijenta, koje se nazivaju i na strani pošiljatelja, da biste slali podatke o OOB i normalne podatke. Na strani poslužitelja, poznat i kao strana prijemnik, koristite dvije utičnice da biste podatke obrađujemo u dvije teme. Jedan je thread za podatke o OOB-u. Druga je nit za normalne podatke. Da biste simulirali mehanizam OOB, morate sinkronizirati ove dvije teme. Provjerite je li nit koja obrađuje podatke o OOB ima veći prioritet od nit koja obrađuje normalne podatke.Napomena Ovaj Ogledni program opisuje jedan način slanja podataka o OOB-u više bajta. Možda ćete morati revidirati kod da bi kod funkcionisali u vašem okruženju.Povratak na gornju

Stvaranje klijentske aplikacije

  1. Stvaranje klijentske aplikacije. U ovoj klijentskoj aplikaciji sljedeći ogledni kod opisuje stvaranje dviju utičnica:

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

    Varijablu Myoobsocket koristi se za slanja podataka o OOB-u. Varijablu Mynormalsocket koristi se za šalje normalne podatke.

  2. Budući da podaci koje varijablu Myoobsocket šalje nisu True OOB podaci, morate imati način na koji možete reći poslužitelju koje vrste podataka koje utičnica treba poslati prije nego što počnete slati podatke. Sljedeći ogledni kod opisuje kako poslati početni znak radi obavještavanja poslužitelja o tome koje vrste podataka će se poslati. Koristite "U" za informacije o OOB i koristite "N" za normalne podatke.

    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. Sljedeći ogledni kod opisuje način na koji klijentska aplikacija može nadzirati unos korisnika. Klijentska aplikacija šalje velikih slova kao OOB podatke. Dupliciranje svakog ulaznog znaka radi sastavljanja niza više bajtova.

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

Prikaz oglednog koda za klijentska aplikacija, Myclient. cpp natrag na vrhu

Stvaranje aplikacije poslužitelja

  1. Na strani poslužitelja sljedeći ogledni kod opisuje kako stvoriti utičnicu slušatelja za praćenje priključka koji se koristi za komunikaciju:

    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. Sljedeći ogledni kod opisuje kako pozivati funkciju prihvaćanje da bi utičnica slušatelja trebala čekati na dolaznih pokušaja povezivanja:

    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. Da biste simulirali mehanizam OOB, morate sinkronizirati ove dvije teme. U ovoj oglednoj aplikaciji koristite globalni objekt događaja za to. Na vrh datoteke postavite sljedeću naredbu.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Stvaranje OOB rukovatelja koji se izvršava zasebnim navojem. U ovom rukovatelju koristite funkciju Select da biste otkrili kada podaci stignu. Kada podaci stignu, slijedite ove korake:

    1. Pozovite funkciju Resetevent da biste postavili objekt događaja hrecvevent na nesignalno stanje.

      ResetEvent(hRecvEvent);

      Time se blokira uobičajeni rukovatelj podacima koji se izvršava u drugoj nit.

    2. Da biste pročitali podatke, pozovite funkciju revc .

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Budući da se više podataka može poslati više nego što međuspremnik može zadržati, ponovno pozovite funkciju primaj , zajedno s zastavom MSG_PEEK , da biste utvrdili jesu li podaci dostupni na žici.

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

      Koristite neku od sljedećih metoda, ovisno o tome postoje li podaci na čekanju za čitanje ili ne:

      • Ako nijedan podatak nije na čekanju za čitanje, pozovite funkciju Setevent za postavljanje određenog objekta događaja u signalno stanje.

        SetEvent(hRecvEvent);

        Kada to učinite, moguće je nastaviti s uobičajenim navojem rukovatelja podacima. Normalna nit rukovatelja podacima čeka objekt događaja Hrecvevent prije no što se ponovno nastavlja nit običnog rukovatelja podataka.

      • Ako su podaci i dalje na čekanju za čitanje, ponovno pozovite funkciju primaj da biste pročitali preostale podatke. Zatim ponovno potražite podatke koji se nalaze na čekanju.

    Ponovite korake od 4a do 4c dok se ne pročitaju svi podaci na čekanju.

  5. Stvaranje normalnog rukovatelja podacima. Ovaj rukovatelj sličan je rukovatelju podacima OOB-a, osim što uobičajeni rukovatelj podacima poziva funkciju Waitforsingleobject kada uobičajeni rukovatelj podacima otkrije da su podaci stigli.

    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.

Prikaz oglednog koda za poslužiteljsku aplikaciju, myserver. cpp natrag na vrhu

Prikaz oglednog koda za klijentska aplikacija, Myclient. cpp

Napomena Morate uvrstiti referencu na datoteku biblioteke Winsock, Ws2_32. lib, da bi se kod kompilirali.

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

Povratak na gornju

Prikaz oglednog koda za poslužiteljsku aplikaciju, myserver. cpp

Napomena Morate uvrstiti referencu na datoteku biblioteke Winsock, Ws2_32. lib, da bi se kod kompilirali.

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

Povratak na gornju

Testiranje uzorka

  1. U naredbeni upit upišite myserver. exe 4444 da biste pokrenuli poslužitelj na servisu Port 4444. aplikacija poslužitelj prikazuje sljedeću poruku, a zatim čeka klijente:

    Poslužitelj je spreman!

  2. U nekom drugom prozoru naredbenog upita upišiteMyclient IPAddress 4444 da biste pokrenuli klijent. Napomena Ipadin rezerviranog mjesta je rezervirano mjesto za IP adresu poslužitelja.

  3. Na poslužitelju se prikazuje poruka slična sljedećoj:

    Waiting.Waiting*..*Kada primite prethodnu poruku, morate upisati Abcdefghi na klijenta u roku od 10 sekundi prije no što se poslužitelj nastavi.

Nakon približno 10 sekundi poslužitelj prikazuje sljedeće:

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [Normal]: Aaaaaaaaaa [normalno]: cccccccccc [Normal]: eeeeeeeeee (Normal]: gggggggggg [Normal]: iiiiiiiiiiPovratak na gornju

Reference

Dodatne informacije potražite na sljedećim web-mjestima programa Microsoft Developer Network (MSDN):

Protokol-nezavisni podaci iz grupe zahttp://msdn2.Microsoft.com/en-us/library/ms740102.aspxWinsock funkcijahttp://msdn2.Microsoft.com/en-us/library/ms741394.aspxDodatne informacije potražite u članku iz Microsoftove baze znanja pod sljedećim brojem:

331756 Funkcija Ioctlsocket ne može prepoznati ugrađene podatke izvan sastavaPovratak na gornju

Potrebna vam je dodatna pomoć?

Želite dodatne mogućnosti?

Istražite pogodnosti pretplate, pregledajte tečajeve za obuku, saznajte kako zaštititi uređaj i još mnogo toga.

Zajednice vam pomažu da postavljate pitanja i odgovarate na njih, pošaljete povratne informacije i čujete se sa stručnjacima s bogatim znanjem.

Jesu li vam ove informacije bile korisne?

Koliko ste zadovoljni jezičnom kvalitetom?
Što je utjecalo na vaše iskustvo?
Ako pritisnete Pošalji, vaše će se povratne informacije iskoristiti za poboljšanje Microsoftovih proizvoda i usluga. Vaš će IT administrator moći prikupiti te podatke. Izjava o zaštiti privatnosti.

Hvala vam na povratnim informacijama!

×