Преминаване към основното съдържание
Поддръжка
Влизане с Microsoft
Влезте или създайте акаунт.
Здравейте,
Изберете друг акаунт.
Имате няколко акаунта
Изберете акаунта, с който искате да влезете.

Обобщена информация

Понякога трябва да изпращате спешни данни за излизане от групата (OOB) към вашите приемници. Приемниците са всички потребители или приложения, които получават данните. Искате тези данни на OOB да се третират като данни с по-висок приоритет от всички нормални данни, които можете да изпратите. Ако данните на OOB, които искате да изпратите, са един байт, можете да използвате функцията Select , за да потърсите данни от OOB. Можете да използвате функцията получи за прочитане на данните. В протокола за управление на пренос (TCP) обаче, блокът за данни на OOB винаги е един байт. Следователно, ако изпращате многобайтови данни за OOB, ще бъдат извлечени само последният байт от данните на OOB. Оставащите данни се третират като нормални данни. Тази статия използва примерен код, за да опише как да изпращате многобайтови данни за OOB с помощта на Microsoft Windows Socket (Winsock).

В ТАЗИ ЗАДАЧА

ВЪВЕДЕНИЕ

Тази статия описва как да изпращате данни за повече байтове (символа) извън групата, като използвате Winsock. Примерните приложения са създадени в Microsoft Visual C++. Тъй като този механизъм на OOB не се поддържа директно на нивото на сокет Microsoft Windows, трябва да реализирате този механизъм за OOB на ниво приложение. Това не е вярно данни за OOB. В това примерно приложение създавате два контакта от страната на клиента, известни също като страна изпращач, за изпращане на данни на OOB и нормални данни. На сървъра страна, известна още като страна на получателя, можете да използвате два контакта, за да обработвате данните в две нишки. Една нишка е за данни на OOB. Другата нишка е за нормалните данни. За да симулирате механизма на OOB, трябва да синхронизирате тези две нишки. Уверете се, че нишката, която обработва данните в OOB, има по-висок приоритет от темата, която обработва нормалните данни.Забележка Тази примерна заявка описва един начин за изпращане на многобайтови данни за OOB. Може да се наложи да коригирате кода, за да направите така, че кодът да работи във вашата среда.обратно в началото

Създаване на клиентско приложение

  1. Създайте клиентско приложение. В това клиентско приложение следния примерен код описва как да създадете два контакта:

    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 се използва за изпращане на данни на OOB. Променливата myNormalSocket се използва за изпращане на нормални данни.

  2. Тъй като данните, които не се изпращат от променливата на myOOBSocket , не са верни OOB данни, трябва да имате начин да укажете на сървъра какви данни би трябвало да изпраща сокетът, преди да започнете да изпращате данни. Следващият примерен код описва как да изпратите първоначален знак, за да уведомите сървъра какви данни ще бъдат изпратени. Използвайте "ф" за данни на OOB и използвайте "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. Следващият примерен код описва как да направите така, че клиентското приложение да наблюдава входящите данни от потребителя. Клиентското приложение изпраща главни букви като данни на OOB. Дублирай всеки входен знак, за да съставите многобайтов низ.

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

Покажи примерния код за клиентското приложение, Myclient. CPP обратно в началото

Създаване на приложение на сървър

  1. На сървъра отстрани следващият примерен код описва как да създадете сокет за слушател, за да следите порт, който се използва за комуникация:

    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. Следващият примерен код описва как да се обадите на функцията Accept , за да изчакате сокетът за слушател, за да се опита да се свърже с вас:

    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, трябва да синхронизирате тези две нишки. В това примерно приложение Използвайте глобален обект за събитие , за да направите това. Поставете следното твърдение в горния край на файла.

    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Създаване на манипулатора на OOB, който се изпълнява с отделен конец. В този манипулатор използвайте функцията Select , за да откривате кога пристигат данни. Когато пристигат данни, изпълнете следните стъпки:

    1. Обадете се на функцията ResetEvent , за да зададете обекта за събития на hRecvEvent на несигнализираното състояние.

      ResetEvent(hRecvEvent);

      Това блокира нормалната ръчка на данни, която се изпълнява в друга нишка.

    2. Извикване на функцията revc за прочитане на данните.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Тъй като още данни могат да бъдат изпратени, отколкото Буферът може да задържи, обадете се на функцията получи отново заедно с флага MSG_PEEK , за да определите дали има налични данни в телта.

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

      Използвайте един от методите по-долу в зависимост от това дали има чакащи данни за четене, или не:

      • Ако няма данни в очакване да бъдат прочетени, обадете се на функцията SetEvent , за да зададете указания обект на събитие към сигнализираното състояние.

        SetEvent(hRecvEvent);

        Когато направите това, нормалната нишка на манипулатора за данни може да се възобнови. Нишката нормален манипулатор на данни изчаква за обекта hRecvEvent Event, преди да се възобнови нормалната нишка за манипулатор на данни.

      • Ако данните все още чакат да бъдат прочетени, обадете се на функцията получи отново, за да прочетете останалите данни. След това потърсете отново очакваните данни.

    Повторете стъпки от 4A до 4, докато всички чакащи данни са прочетени.

  5. Създайте нормален манипулатор за данни. Този манипулатор е подобен на манипулатора за данни на OOB, с изключение на това, че нормалната ръчка на данни извиква функцията WaitForSingleObject , когато нормален манипулатор за данни открие, че данните са пристигнали.

    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.

Показване на примерния код за сървърното приложение myserver. CPP обратно в началото

Показване на примерния код за клиентското приложение, Myclient. CPP

Забележка Трябва да включите препратка към файла на библиотеката Winsock, 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;}

обратно в началото

Показване на примерния код за сървърното приложение myserver. CPP

Забележка Трябва да включите препратка към файла на библиотеката Winsock, 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;}

обратно в началото

Тест на извадката

  1. В командна подкана въведете myserver. exe 4444 , за да стартирате сървъра на порт 4444. приложението Server показва следното съобщение и след това изчаква за клиенти:

    Сървърът е готов!

  2. В друг прозорец на командната подкана въведетеMyClient ipaddress 4444 , за да стартирате клиента. Забележка Контейнерът ipaddress е контейнер за IP адреса на сървъра.

  3. Сървърът показва съобщение, подобно на следното:

    Waiting.Waiting*..*Когато получите предишното съобщение, трябва да въведете aBcDeFgHi в клиента до 10 секунди, преди сървърът да продължи.

След около 10 секунди сървърът показва следното:

[OOB]: BBBBBBBBBB [OOB]: DDDDDDDDDD [OOB]: FFFFFFFFFF [OOB]: HHHHHHHHHH [нормален]: aaaaaaaaaa [нормален]: cccccccccc [нормален]: eeeeeeeeee [нормален]: gggggggggg [нормален]: iiiiiiiiiiобратно в началото

Препратки

За допълнителна информация посетете следните уеб сайтове на мрежата за разработчици на Microsoft (MSDN):

Протокол-независими данни заhttp://msdn2.Microsoft.com/EN-US/Library/ms740102.aspxWinsock за външни функцииhttp://msdn2.Microsoft.com/EN-US/Library/ms741394.aspxЗа допълнителна информация щракнете върху следния номер на статия, за да видите статията в базата знания на Microsoft:

331756 Функцията Ioctlsocket не може да открие вмъкнати данни "извън линия"обратно в началото

Нуждаете ли се от още помощ?

Искате ли още опции?

Разгледайте ползите от абонамента, прегледайте курсовете за обучение, научете как да защитите устройството си и още.

Общностите ви помагат да задавате и отговаряте на въпроси, да давате обратна връзка и да получавате информация от експерти с богати знания.

Беше ли полезна тази информация?

Доколко сте доволни от качеството на езика?
Какво е повлияло на вашия потребителски опит?
Като натиснете „Подаване“, вашата обратна връзка ще се използва за подобряване на продуктите и услугите на Microsoft. Вашият ИТ администратор ще може да събира тези данни. Декларация за поверителност.

Благодарим ви за обратната връзка!

×