Como enviar dados de fora de banda de vários bytes usando Winsock

O suporte para o Windows XP terminou

A Microsoft terminou o suporte para o Windows XP em 8 de abril de 2014. Esta alteração afetou as suas atualizações de software e opções de segurança. Saiba o que isto significa para você e como permanecer protegido.

O suporte para o Windows Server 2003 termina em 14 de julho de 2015.

A Microsoft terminou o suporte para o Windows Server 2003 em 14 de julho de 2015. Esta alteração afetou as suas atualizações de software e opções de segurança. Saiba o que isto significa para você e como permanecer protegido.

IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine Translation ou MT), não tendo sido portanto traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes ao software de tradução automática (MT). Obrigado.

Clique aqui para ver a versão em Inglês deste artigo: 830597
Sumário
às vezes, você deve enviar dados urgentes out-of-band () para seus destinatários. Receptores são todos os usuários ou aplicativos que recebem os dados. Você deseja que este dados OOB tratados como dados de prioridade mais alta que quaisquer dados normais que você pode enviar. Se os dados OOB que você deseja enviar um byte, você pode usar a função Selecione para procurar dados OOB. Você pode usar a função recv para ler os dados.

No entanto, em TCP (Transmission Control Protocol), o bloco de dados OOB é sempre um byte. Portanto, se você enviar vários bytes OOB dados, apenas o último byte de dados OOB é recuperado. Os dados restantes são tratados como dados normais.

Este artigo usa código de exemplo para descrever como enviar vários bytes OOB dados usando o Microsoft Windows Socket (Winsock).
INTRODUÇÃO
Este artigo descreve como enviar dados de fora de banda de vários bytes (caracteres) usando o Winsock. Os aplicativos de exemplo são criados no Microsoft Visual C++.

Porque esse mecanismo OOB não oferece suporte diretamente no nível de soquete do Microsoft Windows, você deve implementar esse mecanismo OOB no nível do aplicativo. Isso não é true OOB dados. Neste exemplo de aplicativo, você cria dois soquetes no lado do cliente, também conhecido como o lado do remetente, para enviar dados OOB e dados normais. No lado do servidor, também conhecido como lado do receptor, você usa dois soquetes para processar os dados em dois segmentos. Um segmento é para OOB dados. O outro thread é para dados normais.

Para simular o mecanismo OOB, você deve sincronizar esses dois segmentos. Verifique se o thread que processa dados OOB tem prioridade maior que o thread que processa dados normais.

Observação Esse aplicativo de exemplo descreve uma maneira de enviar dados OOB multibyte. Talvez você precise revisar o código para tornar o código funcionar no seu ambiente.

back to the top

Criar um aplicativo cliente

  1. Crie um aplicativo cliente. Neste aplicativo cliente, o código de exemplo a seguir descreve como criar dois soquetes:
    SOCKET myOOBSocket = INVALID_SOCKET;SOCKET myNormalSocket = INVALID_SOCKET;myOOBSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);myNormalSocket = socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    a variável myOOBSocket é usada para enviar dados OOB. A variável myNormalSocket é usada para enviar dados normais.
  2. Como os dados que envia a variável myOOBSocket não são true OOB dados, você deve ter uma maneira de informar o servidor que tipo de dados que o soquete deve para enviar antes de você iniciar o envio de dados. O código de exemplo a seguir descreve como enviar um caractere inicial para notificar o servidor sobre que tipo de dados que serão enviados. Use "U" para OOB dados e usar "N" para dados normais.
    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. O código de exemplo a seguir descreve como tornar o aplicativo cliente monitorar a entrada do usuário. O aplicativo cliente envia caracteres maiúsculos como OOB dados. Duplica cada caractere de entrada para redigir uma seqüência de vários bytes.
    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);	}	...}
Display the sample code for the client application, Myclient.cpp

back to the top

Criar um aplicativo de servidor

  1. No lado do servidor, o código de exemplo a seguir descreve como criar um soquete de escuta para monitorar a porta que é usada para comunicação:
    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. O código de exemplo a seguir descreve como chamar a função Aceitar para criar o soquete de escuta esperar para tentativas de conexão de entrada:
    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. Para simular o mecanismo OOB, você deve sincronizar esses dois segmentos. Neste exemplo de aplicativo, use um objeto de evento global para fazer isso. Coloque a instrução a seguir na parte superior da file.
    //Create a manual-reset event object. hRecvEvent=CreateEvent(NULL,TRUE,TRUE,"RecvEvent");
  4. Crie o manipulador OOB que é executado por um thread separado. Nesse manipulador, você usar a função Selecione para detectar quando os dados chegam. Quando os dados chegam, execute essas etapas:
    1. Chame a função ResetEvent para definir o objeto de evento hRecvEvent para o estado não sinalizado.
      ResetEvent(hRecvEvent);
      Isso bloqueia o manipulador de dados normal que é executado em outro thread.
    2. Chamar a função revc para ler os dados.
      recv(remoteSocket,(char *)&buffer,sizeof(buffer) - 1,0);
    3. Porque mais os dados podem ser enviados que o buffer pode comportar, chame a função recv novamente, junto com o sinalizador MSG_PEEK , para determinar se os dados estão disponíveis na conexão. recv
      recv(remoteSocket,(char *)&buffer,sizeof(buffer)-1,MSG_PEEK);
      use um dos seguintes métodos, dependendo se há dados pendentes para ser lido ou não:
      • Se nenhum dado for pendente para ser lido, chame a função SetEvent para definir o objeto de evento especificado para o estado sinalizado.
        SetEvent(hRecvEvent);
        Quando você fizer isso, o thread de manipulador de dados normal pode continuar. O segmento de manipulador de dados normais espera para o objeto de evento hRecvEvent antes do segmento de manipulador de dados normal continua.
      • Se dados é ainda pendente para ser lido, chame a recv função novamente para ler os dados restantes. Em seguida, procure novamente pendentes dados.
    Repita as etapas 4a até 4 c até que todos os dados pendentes foi lida.
  5. Crie o manipulador de dados normais. Esse manipulador é semelhante para o manipulador de dados OOB exceto que o manipulador de dados normais chama a função WaitForSingleObject quando o manipulador de dados normais detecta que dados chegou.
    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.
Display the sample code for the server application, Myserver.cpp

back to the top

Exibir o código de exemplo para o aplicativo cliente, Myclient.cpp

Observação Você deve incluir uma referência para o arquivo de biblioteca Winsock, Ws2_32.lib, para tornar o código compilar.
#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;}
back to the top

Exibir o código de exemplo para o aplicativo do servidor, Myserver.cpp

Observação Você deve incluir uma referência para o arquivo de biblioteca Winsock, Ws2_32.lib, para tornar o código compilar.
#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;}
back to the top

Testar o exemplo

  1. Em um prompt de comando, digite Myserver.exe 4444 para iniciar o servidor na porta 4444.

    O aplicativo do servidor exibirá a mensagem a seguir e aguarda que os clientes:

    O servidor está pronto!
  2. Em uma janela diferente do prompt de comando, digite myClient IPAddress 4444 para iniciar o cliente.

    Observação O espaço reservado para IPAddress é um espaço reservado para o endereço IP do servidor.
  3. O servidor exibirá uma mensagem semelhante à seguinte:

    Waiting.Waiting**


    Quando você receber a mensagem anterior, você deve digitar aBcDeFgHi no cliente em 10 segundos antes do servidor continua.
Após cerca de 10 segundos, o servidor exibe a seguinte:
[OOB]: BBBBBBBBBB
[OOB]: DDDDDDDDDD
[OOB]: FFFFFFFFFF
[OOB]: HHHHHHHHHH
[Normal]: aaaaaaaaaa
[Normal]: cccccccccc
[Normal]: eeeeeeeeee
[Normal]: gggggggggg
[Normal]: iiiiiiiiii
back to the top
Referências
Para obter informações adicionais, visite o seguinte da Microsoft Developer Network (MSDN):Para obter informações adicionais, clique no número abaixo para ler o artigo na Base de dados de Conhecimento da Microsoft:
331756A função Ioctlsocket não pode detectar dados de fora de banda in-line
back to the top
OOB mensagem winsock selecione vários detectar SO_OOBINLINE ioctlsocket MSG_OOB; SIOCATMARK

Aviso: este artigo foi traduzido automaticamente

Propriedades

ID do Artigo: 830597 - Última Revisão: 01/19/2007 08:54:37 - Revisão: 2.1

Microsoft Windows 2000 Professional Edition, Microsoft Windows 2000 Server, Microsoft Windows 2000 Advanced Server, Microsoft Windows 2000 Datacenter Server, Microsoft Windows XP Home Edition, Microsoft Windows XP Professional, Microsoft Windows Server 2003, Standard Edition (32-bit x86), Microsoft Windows Server 2003, Enterprise Edition (32-bit x86), Microsoft Windows Server 2003, Datacenter Edition (32-bit x86)

  • kbmt kbhowto kbnetwork kbinfo KB830597 KbMtpt
Comentários