Slik sender du flere byte out-of-band-data ved hjelp av Winsock

Sammendrag

Noen ganger må du sende viktige out-of-band (OOB) data til dine mottakere. Mottakere er alle brukere eller programmer som kan mottar data. Du vil skal behandles som data for høyere prioritet enn normal data som du kan sende denne OOB-dataene. Hvis OOB-dataene som du vil sende, er én byte, kan du bruke funksjonen velger for å søke etter OOB-data. Du kan bruke funksjonen Motta for å lese dataene.

I Transmission Control Protocol (TCP) er OOB-datablokken imidlertid alltid én byte. Hvis du sender flere byte OOB data, hentes derfor bare den siste byten OOB-data. De gjenværende dataene behandles som vanlige data.

Denne artikkelen bruker eksempelkoden til å beskrive hvordan du sender flere byte OOB-data ved hjelp av Microsoft Windows-brikke (Winsock).

I DENNE OPPGAVEN

INTRODUKSJON

Denne artikkelen beskriver hvordan du sender flere-byte (tegn) out-of-band-data ved hjelp av Winsock. Eksempelprogrammer er opprettet i Microsoft Visual C++.

Fordi denne mekanismen OOB ikke støttes direkte på Microsoft Windows socket-nivå, må du implementere denne OOB-mekanismen på programnivå. Dette er ikke sant OOB-data. I dette eksemplet programmet oppretter du to brikker på klientsiden, også kjent som sender siden til å sende OOB-data og vanlige data. På serversiden, også kjent som mottakeren siden, kan du bruke to brikker til å behandle dataene i to tråder. Det er én tråd for OOB-data. Den andre tråden er for vanlige data.


Hvis du vil simulere OOB-mekanismen, må du synkronisere disse to tråder. Kontroller at tråden som behandler data for OOB har høyere prioritet enn tråden som behandler vanlige data.

Obs! Dette eksempelprogrammet beskriver en måte å sende multibyte OOB-data. Du må kanskje endre kode for å gjøre koden fungerer i ditt miljø.

tilbake til toppen

Opprette et klientprogram

  1. Opprette et klientprogram. Følgende eksempelkode beskriver hvordan du oppretter to brikker i dette klientprogrammet:

    SOCKET myOOBSocket = INVALID_SOCKET;
    SOCKET myNormalSocket = INVALID_SOCKET;

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

    Variabelen myOOBSocket brukes til å sende OOB-data. Variabelen myNormalSocket brukes til å sende vanlig data.

  2. Fordi dataene som variabelen myOOBSocket sender ikke er oppfylt OOB-data, må du ha en måte å fortelle hva slags data som socket skulle sendt før du starter sending av data for serveren. Følgende eksempelkode beskriver hvordan du sender et innledende tegn til å varsle serveren om hva slags data som skal sendes. Bruk "U" for OOB-data, og bruk "N" for normal data.

    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. Følgende eksempelkode beskriver hvordan du gjør klientprogrammet overvåke inndata fra brukeren. Klientprogrammet sender store bokstaver som OOB-data. Like alle inndata tegn hvis du vil skrive en streng med flere byte.

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

Vise eksempelkode for klientprogrammet, Myclient.cpp

tilbake til toppen

Opprette et serverprogram

  1. Følgende eksempelkode beskriver hvordan du oppretter en lytte-socket for å overvåke porten som brukes for kommunikasjon på serversiden:

    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. Følgende eksempelkode beskriver hvordan til å kalle funksjonen Godta for å gjøre lytteobjektsocket vente for innkommende tilkobling forsøk:

    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. Hvis du vil simulere OOB-mekanismen, må du synkronisere disse to tråder. I dette eksemplet programmet Bruk en global hendelsesobjektet til dette. Legge til følgende setning øverst i filen.

    //Create a manual-reset event object. 
    hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Opprette OOB behandlingsprogrammet som er utført av en egen tråd. I dette behandlingsprogrammet, kan du bruke Velg -funksjonen til å oppdage når data kommer. Når dataene kommer inn, gjør du følgende:

    1. Kall ResetEvent -funksjonen hvis du vil angi ikke-signalisert status hendelsesobjektet hRecvEvent .

      ResetEvent(hRecvEvent);

      Dette blokkerer vanlige data behandlingsprogrammet som er utført i en annen tråd.

    2. Kall revc -funksjonen for å lese dataene.

      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Fordi flere data kan sendes enn bufferen kan ha, kan du kalle funksjonen Motta på nytt, sammen med flagget MSG_PEEK å finne ut om data er tilgjengelig på nettverket.

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

      Bruk en av følgende metoder, avhengig av om det er ventende data leses eller ikke:

      • Hvis ingen data er ventende leses, kan du ringe SetEvent -funksjonen hvis du vil angi signalisert status hendelsesobjektet som er angitt.

        SetEvent(hRecvEvent);

        Når du gjør dette, kan normale data handler tråden fortsette. Normal data handler tråden venter på hendelsesobjektet hRecvEvent før normal data handler tråden fortsetter.

      • Hvis dataene er venter fortsatt leses, kaller funksjonen Motta på nytt for å lese de gjenværende dataene. Deretter ser du på nytt ventende data.

    Gjenta trinn 4a til og med 4c til alle ventende data er lest.

  5. Opprett vanlig data-behandling. Dette behandlingsprogrammet ligner OOB data behandling bortsett fra at normal data-behandleren kaller funksjonen WaitForSingleObject når normal data behandlingsprogrammet oppdager at data er mottatt.

    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.

Vise eksempelkode for serverprogrammet, Myserver.cpp

tilbake til toppen

Vise eksempelkode for klientprogrammet, Myclient.cpp

Obs! Du må inkludere en referanse til filen Winsock-biblioteket, Ws2_32.lib, slik at koden kompileres.

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

tilbake til toppen

Vise eksempelkode for serverprogrammet, Myserver.cpp

Obs! Du må inkludere en referanse til filen Winsock-biblioteket, Ws2_32.lib, slik at koden kompileres.

#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;
else
printf("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;
}

tilbake til toppen

Teste prøven

  1. Ved ledeteksten, skriver du inn Myserver.exe 4444 for å starte serveren på port 4444.

    Serverprogrammet viser følgende melding og venter deretter på klienter:

    Serveren er klart!

  2. I et annet vindu i ledeteksten skriver du inn
    myClient IP-adresse 4444 for å starte klienten.

    Obs! Plassholder -IP-adresse er en plassholder for IP-adressen til serveren.

  3. Serveren viser en melding som ligner på følgende:

    Waiting.Waiting*..*

    Når du mottar den forrige meldingen, må du skrive aBcDeFgHi på klienten i løpet av 10 sekunder før serveren fortsetter.

Etter omtrent 10 sekunder viser serveren følgende:

[OOB]: BBBBBBBBBB
[OOB]: DDDDDDDDDD
[OOB]: FFFFFFFFFF
[OOB]: HHHHHHHHHH

[Normal]: aaaaaaaaaa
[Normal]: cccccccccc
[Normal]: eeeeeeeeee

[Normal]: gggggggggg
[Normal]: iiiiiiiiiitilbake til toppen

Referanser

Hvis du vil ha mer informasjon, kan du gå til følgende webområder for Microsoft Developer Network (MSDN):

Protokoll-uavhengig out-of-band-data
http://msdn2.microsoft.com/en-us/library/ms740102.aspx

Winsock-funksjoner
http://msdn2.microsoft.com/en-us/library/ms741394.aspxHvis du vil ha mer informasjon, kan du klikke følgende artikkelnummer for å vise artikkelen i Microsoft Knowledge Base:

331756 i Ioctlsocket-funksjonen finner ikke innebygd out-of-band-data

tilbake til toppen

Trenger du mer hjelp?

Utvid ferdighetene dine
Utforsk opplæring
Vær først ute med de nye funksjonene
Bli med i Microsoft Insiders

Var denne informasjonen nyttig?

Takk for tilbakemeldingen!

×