Salt la conținutul principal
Asistență
Conectare

Cum se trimite date out-of-Band mai multe octet utilizând Winsock

Rezumat

Uneori trebuie să trimiteți la receptoare date de urgență out-of-Band (OOB). Receptoarele sunt utilizatori sau orice aplicații care primesc datele. Doriți ca aceste date OOB să fie tratate ca date cu prioritate mai mare decât orice date normale pe care le puteți trimite. Dacă datele OOB pe care doriți să le trimiteți sunt un octet, puteți utiliza funcția Select pentru a căuta date OOB. Puteți utiliza funcția primire pentru a citi datele. Cu toate acestea, în Protocolul de control al transmisiei (TCP), blocul de date OOB este întotdeauna un octet. Prin urmare, dacă trimiteți mai multe date OOB, se va regăsi doar ultimul octet din datele OOB. Datele rămase sunt tratate ca date normale. Acest articol utilizează exemple de cod pentru a descrie cum se trimit date OOB mai multe octet utilizând Microsoft Windows socket (Winsock).

ÎN ACEASTĂ ACTIVITATE

INTRODUCERE

Acest articol descrie cum se trimit date de tip mai multe octeți (caractere) utilizând Winsock. Aplicațiile eșantion sunt create în Microsoft Visual C++. Deoarece acest mecanism OOB nu este acceptat direct la nivelul socket-ului Microsoft Windows, trebuie să implementați acest mecanism OOB la nivel de aplicație. Acest lucru nu este adevărat OOB date. În această aplicație eșantion, creați două socketuri pe partea client, denumită și parte expeditor, pentru a trimite date OOB și date normale. Pe partea de server, denumită și parte receptor, utilizați două socketuri pentru a prelucra datele în două fire. Un fir este pentru date OOB. Celălalt fir este pentru date normale. Pentru a simula mecanismul OOB, trebuie să sincronizați aceste două fire. Asigurați-vă că firul care procesează datele OOB are o prioritate mai mare decât firul care procesează datele normale.Notă Această aplicație eșantion descrie o modalitate de a trimite date OOB multi-octet. Poate fi necesar să revizuiți codul pentru a face codul să funcționeze în mediul dvs.înapoi la început

Crearea unei aplicații client

  1. Creați o aplicație client. În această aplicație client, următorul exemplu de cod descrie cum se creează două socketuri:

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

    Variabila myOOBSocket este utilizată pentru a trimite date OOB. Variabila myNormalSocket este utilizată pentru a trimite date normale.

  2. Deoarece datele pe care le trimite variabila myOOBSocket nu sunt adevărate OOB date, trebuie să aveți o modalitate de a spune serverului ce tip de date ar trebui să trimită socket-ul înainte de a începe să trimiteți date. Următorul exemplu de cod descrie cum se trimite un caracter inițial pentru a notifica serverul despre tipul de date care vor fi trimise. Utilizați "U" pentru date OOB și utilizați "N" pentru date normale.

    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. Următorul exemplu de cod descrie cum să faceți ca aplicația client să monitorizeze intrarea utilizatorului. Aplicația client trimite caractere majuscule ca date OOB. Dublați fiecare caracter de intrare pentru a compune un șir de octeți multipli.

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

Afișați codul eșantion pentru aplicația client, Myclient. cpp înapoi la început

Crearea unei aplicații de server

  1. În partea server, următorul exemplu de cod descrie cum se creează un socket ascultător pentru a monitoriza portul utilizat pentru comunicare:

    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. Următorul exemplu de cod descrie modul de apelare a funcției acceptare pentru a face ca mufa ascultătorului să aștepte încercarea de conexiune de intrare:

    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. Pentru a simula mecanismul OOB, trebuie să sincronizați aceste două fire. În această aplicație eșantion, utilizați un obiect eveniment global pentru a face acest lucru. Puneți următoarea instrucțiune în partea de sus a fișierului.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Creați rutina de tratare OOB care este executată de un fir separat. În acest handler, utilizați funcția Select pentru a detecta când sosesc date. Când sosesc date, urmați acești pași:

    1. Apelați funcția ResetEvent pentru a seta obiectul evenimentului hRecvEvent la starea fără semnalizare.

      ResetEvent(hRecvEvent);

      Aceasta blochează rutina de tratare a datelor normală care este executată în alt fir.

    2. Apelați funcția revc pentru a citi datele.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Deoarece mai multe date pot fi trimise decât poate stoca tamponul, apelați din nou funcția primire , împreună cu semnalizarea MSG_PEEK , pentru a determina dacă sunt disponibile date pe sârmă.

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

      Utilizați una dintre următoarele metode, în funcție de faptul dacă există date în curs de citire sau nu:

      • Dacă nu este așteptată nicio dată pentru a fi citit, apelați funcția SetEvent pentru a seta obiectul evenimentului specificat la starea semnalată.

        SetEvent(hRecvEvent);

        Atunci când procedați astfel, firul normal de tratare a datelor poate fi reluat. Firul normal de tratare a datelor așteaptă obiectul evenimentului hRecvEvent înainte ca firul normal de tratare a datelor să reia.

      • Dacă datele sunt încă în curs de citire, apelați din nou funcția primire pentru a citi datele rămase. Apoi, căutați din nou date în așteptare.

    Repetați pașii de la 4a până la 4C până când toate datele în așteptare au fost citite.

  5. Creați rutina de tratare a datelor obișnuite. Acest handler este similar cu rutina de tratare a datelor OOB, cu excepția faptului că rutina obișnuită de tratare a datelor apelează funcția WaitForSingleObject atunci când rutina obișnuită de tratare a datelor detectează că datele au sosit.

    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.

Afișați codul eșantion pentru aplicația server, myserver. cpp înapoi la început

Afișarea codului eșantion pentru aplicația client, Myclient. cpp

Notă Trebuie să includeți o referință la fișierul bibliotecă Winsock, Ws2_32. lib, pentru a face codul să compileze.

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

înapoi la început

Afișarea codului eșantion pentru aplicația server, myserver. cpp

Notă Trebuie să includeți o referință la fișierul bibliotecă Winsock, Ws2_32. lib, pentru a face codul să compileze.

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

înapoi la început

Testarea eșantionului

  1. În linia de comandă, tastați myserver. exe 4444 pentru a porni serverul pe portul 4444. aplicația server afișează următorul mesaj, apoi așteaptă clienți:

    Serverul este gata!

  2. Într-o altă fereastră de linie de comandă, tastațiMyClient Ipaddress 4444 pentru a porni clientul. Notă Ipaddress substituent este un substituent pentru adresa IP a serverului.

  3. Serverul afișează un mesaj asemănător cu următorul:

    Waiting.Waiting*..*Când primiți mesajul anterior, trebuie să tastați aBcDeFgHi pentru client în termen de 10 secunde înainte ca serverul să continue.

După aproximativ 10 secunde, serverul afișează următoarele:

[OOB]: Sara [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [normal]: ailenei [normal]: Constantin [normal]: eeeeeeeeee [normal]: gggggggggg [normal]: iiiiiiiiiiînapoi la început

Referințe

Pentru informații suplimentare, vizitați următoarele site-uri Web Microsoft Developer Network (MSDN):

Protocoale independente de datehttp://msdn2.Microsoft.com/en-us/library/ms740102.aspxWinsockhttp://msdn2.Microsoft.com/en-us/library/ms741394.aspxPentru informații suplimentare, faceți clic pe următorul număr de articol pentru a vedea articolul în baza de cunoștințe Microsoft:

331756 Funcția Ioctlsocket nu poate detecta date din bandă în linieînapoi la început

Aveți nevoie de ajutor suplimentar?

Extindeți-vă competențele
Explorați instruirea
Fiți primul care obține noile caracteristici
Alăturați-vă la Microsoft Insider

V-a fost de ajutor această informație?

Vă mulțumim pentru feedback!

Vă mulțumim pentru feedback! Se pare că ar fi util să luați legătura cu unul dintre agenții noștri de asistență Office.

×