Friday 21 September 2018

Winsock send data binary options


Tutorial de programação PHP Socket Sockets Php e tcpip Este é um guia rápido para aprender a programação de soquetes no php. Socket programming php é muito semelhante ao C. A maioria das funções são semelhantes nos nomes, parâmetros e saída. No entanto, ao contrário de C, os programas de soquetes escritos em php funcionariam da mesma forma em qualquer um que tenha instalado o php. Portanto, o código não precisa de mudanças específicas da plataforma (principalmente). Para resumir o básico, os soquetes são as coisas fundamentais de qualquer tipo de comunicação de rede feita pelo seu computador. Por exemplo, quando você digita google no seu navegador da Web, ele abre um soquete e se conecta ao google para buscar a página e mostrá-lo para você. Mesmo com qualquer cliente de bate-papo como o Gtalk ou o Skype. Qualquer comunicação de rede passa por um soquete. Antes de começar Este tutorial pressupõe que você já conhece o php e também como executar scripts php do comandolineterminal. Os scripts Php são normalmente executados a partir do interior do navegador, colocando-os no diretório raiz apache como var, no entanto, esses programas de linha de comando podem ser executados a partir de qualquer diretório. Eles também podem ser executados a partir de navegadores. Então vamos começar com soquetes. Criando um soquete Esta primeira coisa a fazer é criar um soquete. A função socketcreate faz isso. Aqui está um exemplo de código: a função socketcreate cria um soquete e retorna um descritor de soquete que pode ser usado em outros comandos de rede. O código acima criará um soquete com as seguintes propriedades. Endereço Família. AFINET (esta é a versão IP 4) Digite. SOCKSTREAM (isto significa protocolo TCP orientado a conexão). 0 ou IPPROTOIP Este é o protocolo IP Se alguma das funções do soquete falhar, as informações de erro podem ser recuperadas usando as funções socketlasterror e socketstrerror. Está bem. Então você criou um soquete com sucesso. Mas o que vem depois. Em seguida, devemos tentar conectar-se a algum servidor usando este soquete. Podemos nos conectar ao Google Além do tipo de soquetes SOCKSTREAM, existe outro tipo chamado SOCKDGRAM que indica o protocolo UDP. Este tipo de soquete é um soquete de não conexão. Neste tutorial, devemos manter os soquetes SOCKSTREAM ou TCP. Conecte-se a um Servidor Conectamos a um servidor remoto em um determinado número de porta. Então precisamos de 2 coisas. Endereço IP e número de porta para se conectar. Então, você precisa saber o endereço IP do servidor remoto ao qual você está se conectando. Aqui usamos o endereço IP do google como amostra. Um pouco mais tarde, veremos como descobrir o endereço IP de um determinado nome de domínio. A última coisa necessária é a função de conexão. Ele precisa de um soquete e uma estrutura sockaddr para se conectar. Aqui está um exemplo de código. Execute o programa php varwwwsocket. php Socket criado Conexão estabelecida Ele cria um soquete e depois se conecta. Tente conectar-se a uma porta diferente da porta 80 e você não deve se conectar, o que indica que a porta não está aberta para conexão. Essa lógica pode ser usada para construir um scanner de portas. OK, então estamos conectados. Vamos fazer a próxima coisa. Enviando alguns dados para o servidor remoto. O conceito de conexões se aplica ao tipo de sockets SOCKSTREAMTCP. Conexão significa um fluxo confiável de dados, de modo que pode haver vários desses fluxos cada um tendo comunicação própria. Pense nisso como um tubo que não é interferido por outros dados. Outros soquetes como o UDP. ICMP. ARP não tem um conceito de conexão. Estas são comunicação não relacionada à conexão. O que significa que você continua enviando ou recebendo pacotes de todos e de todos. O envio de função de dados enviada simplesmente enviará dados. Ele precisa do descritor do soquete. Os dados a serem enviados e seu tamanho. Aqui está um exemplo muito simples de enviar alguns dados para o google ip: no exemplo acima. Primeiro nos conectamos a um endereço IP e, em seguida, enviamos a mensagem de cadeia GET HTTP1.1rnrn para ele. A mensagem é, na verdade, um comando http para buscar a página principal de um site. Agora que enviamos alguns dados. É hora de receber uma resposta do servidor. Então, vamos fazê-lo. Ao enviar dados para um soquete você basicamente está escrevendo dados para esse soquete. Isso é semelhante à escrita de dados em um arquivo. Portanto, você também pode usar a função de gravação para enviar dados para um soquete. Mais tarde, neste tutorial, devemos usar a função de gravação para enviar dados. Recebendo dados A função recv é usada para receber dados em um soquete. No exemplo a seguir, enviaremos a mesma mensagem como o último exemplo e receberemos uma resposta do servidor. Aqui está a saída do código acima: podemos ver qual resposta foi enviada pelo servidor. Parece algo como Html, bem, é html. O Google respondeu com o conteúdo da página que solicitamos. Bastante simples Agora que recebemos nossa resposta, é hora de fechar o soquete. Soquete fechado A função socketclose é usada para fechar o soquete. Vamos Rever Assim, no exemplo acima, aprendemos como: 1. Criar um soquete 2. Conectar ao servidor remoto 3. Enviar alguns dados 4. Receber uma resposta É útil saber que seu navegador também faz a mesma coisa quando abre o google Esse tipo de atividade de soquete representa um CLIENTE. Um cliente é um sistema que se conecta a um sistema remoto para buscar dados. O outro tipo de atividade de soquete é chamado de SERVER. Um servidor é um sistema que usa sockets para receber conexões recebidas e fornecer dados. É exatamente o oposto do Cliente. Portanto, o google é um servidor e seu navegador é um cliente. Ou, mais tecnicamente, o google é um servidor HTTP e seu navegador web é um cliente HTTP. Agora é hora de fazer algumas tarefas do servidor usando sockets. Mas antes de seguir em frente, existem alguns tópicos secundários que devem ser cobertos apenas se você precisar deles. Obter o endereço IP de um hostnamedomain Ao se conectar a um host remoto. É necessário ter seu endereço IP. A função gethostbyname é usada para este propósito. Ele leva o nome do domínio como o parâmetro e retorna o endereço IP. Portanto, o código acima pode ser usado para encontrar o endereço IP de qualquer nome de domínio. Então, o endereço IP pode ser usado para fazer uma conexão usando um soquete. Programação de servidor OK agora em coisas do servidor. Os servidores basicamente fazem o seguinte: 1. Abra um soquete 2. Vincule a um endereço (e porta). 3. Ouça as conexões recebidas. 4. Aceitar conexões 5. ReadSend Já aprendemos a abrir um soquete. Então, a próxima coisa seria obrigá-lo. Vincular um soquete O bind de função pode ser usado para vincular um soquete a um endereço e porta específicos. Ele precisa de uma estrutura sockaddrin semelhante à função de conexão. Agora que o bind está pronto, é hora de fazer o socket ouvir as conexões. Nós ligamos um soquete a um endereço IP específico e um determinado número de porta. Ao fazer isso, garantimos que todos os dados recebidos direcionados para este número de porta sejam recebidos por este aplicativo. Isso torna óbvio que você não pode ter 2 soquetes vinculados à mesma porta. Há exceções a esta regra, mas devemos analisar isso em algum outro artigo. Ouvir conexões Depois de ligar um soquete a uma porta, a próxima coisa que precisamos fazer é ouvir conexões. Para isso precisamos colocar o soquete no modo de audição. Função socketlisten é usado para colocar o soquete no modo de audição. Basta adicionar a seguinte linha após ligar. O segundo parâmetro da função socketlisten é chamado de backlog. Ele controla o número de conexões recebidas que estão aguardando se o programa já estiver ocupado. Então, ao especificar 10, isso significa que se 10 conexões já estiverem aguardando processamento, então o 11º pedido de conexão deve ser rejeitado. Isso será mais claro depois de verificar socketaccept. Agora vem a principal parte da aceitação de novas conexões. Aceitar conexão Função socketaccept é usado para isso. Execute o programa. Ele deve mostrar php varwwwserver. php Socket criado Socket bind OK Socket listen OK Esperando conexões recebidas. Então, agora, este programa está aguardando conexões recebidas na porta 5000. Não feche este programa. Mantenha-o em funcionamento. Agora, um cliente pode se conectar a ele nesta porta. Devemos usar o cliente telnet para testar isso. Abra um terminal e digite telnet localhost 5000 Ele mostrará imediatamente o telnet localhost 5000 Tentando 127.0.0.1. Conectado ao localhost. O personagem de escape é. Conexão fechada por host estrangeiro. E a saída do servidor mostrará o Cliente 127.0.0.1. 36689 agora está conectado a nós. Então, podemos ver que o cliente está conectado ao servidor. Experimente os passos acima até conseguir que ele seja perfeito. A função socketgetpeername é usada para obter detalhes sobre o cliente que está conectado ao servidor através de um soquete particular. Aceitamos uma conexão de entrada, mas fechamos imediatamente. Isso não foi muito produtivo. Há muitas coisas que podem ser feitas depois que uma conexão entrante é estabelecida. Depois de tudo, a conexão foi estabelecida para fins de comunicação. Então, responda ao cliente. A função socketwrite pode ser usada para escrever algo no soquete da conexão de entrada e o cliente deve vê-lo. Aqui está um exemplo: Execute o código acima em 1 terminal. E conecte-se a este servidor usando telnet de outro terminal e você deve ver isso: então o cliente (telnet) recebeu uma resposta do servidor. Podemos ver que a conexão é fechada imediatamente depois disso simplesmente porque o programa do servidor termina depois de aceitar e enviar a resposta. Um servidor como o Google sempre aceita conexões recebidas. Isso significa que um servidor deveria estar funcionando o tempo todo. Afterall é um servidor destinado a servir. Portanto, precisamos manter o nosso servidor de FUNCIONAMENTO sem parar. A maneira mais simples de fazer isso é colocar o aceitar em um loop para que ele possa receber conexões recebidas o tempo todo. Servidor ao vivo Então, um servidor ao vivo estará sempre vivo. Permite codificar isso. Não conseguimos muito lá. Basta colocar o socketaccept em um loop. Agora execute o programa do servidor em 1 terminal. E abra 3 outros terminais. De cada um dos 3 terminais faça um telnet para a porta do servidor. Cada um dos terminais telnet mostraria: telnet localhost 5000 Tentando 127.0.0.1. Conectado ao localhost. O personagem de escape é. Feliz OK. Conexão feliz fechada por host estrangeiro. E o terminal do servidor mostraria php varwwwserver. php Socket criado Socket bind OK Socket listen OK Esperando as conexões recebidas. Cliente 127.0.0.1. 37119 agora está conectado a nós. Cliente 127.0.0.1. 37122 agora está conectado a nós. Cliente 127.0.0.1. 37123 agora está conectado a nós. Então, agora, o servidor está funcionando sem parar e os terminais telnet também estão conectados sem interrupção. Agora, feche o programa do servidor. Todos os terminais telnet mostrarão conexão fechada por host externo. Bom até agora. Mas ainda não existe comunicação efetiva entre o servidor e o cliente. O programa do servidor aceita conexões em um loop e apenas envia-lhes uma resposta, depois não faz nada com elas. Também não é capaz de lidar com mais de 1 conexão por vez. Então agora é hora de lidar com as conexões. E lidar com múltiplas conexões em conjunto. Manipulação de conexões Para lidar com todas as conexões, precisamos de um código de manipulação separado para executar junto com o servidor principal que aceita conexões. Uma maneira de conseguir isso é usar threads. O programa do servidor principal aceita uma conexão e cria um novo tópico para lidar com a comunicação para a conexão e, em seguida, o servidor volta a aceitar mais conexões. No entanto, o php não suporta o threading diretamente. Outro método é usar a função de seleção. A função de seleção basicamente pesquisa ou observa um conjunto de soquetes para determinados eventos, como se fosse legível ou gravável ou teve um problema ou não, etc. Portanto, a função de seleção pode ser usada para monitorar vários clientes e verificar qual cliente enviou uma mensagem. Execute o servidor acima e abra 3 terminais como antes. Agora, o servidor criará um segmento para cada cliente que se conecte a ele. Os terminais de telnet mostrariam: O terminal do servidor pode parecer assim. O manipulador de conexão acima leva alguma entrada do cliente e responde de volta com o mesmo. Simples Aqui está como a saída do telnet pode parecer Então agora temos um servidor que é comunicativo. Isso é útil agora. Conclusão Até agora, você deve ter aprendido os conceitos básicos de programação de socket em php. Você pode experimentar algumas experiências, como escrever um cliente de bate-papo ou algo semelhante. Se você acha que o tutorial precisa de alguns complementos ou melhorias ou qualquer um dos trechos de código acima, não trabalhe, então, sinta-se livre para fazer um comentário abaixo para que ele consiga corrigir. Última atualização em. 26 de março de 2017Dados binários de transmissão via protocolo UDP (Winsock) Eu estou fazendo um programa cliente que requer que os dados binários sejam enviados para o servidor através do protocolo UDP. (Eu uso o controle winsock) Eu tenho usado o seguinte código. Dim ByteX como Byte Dim X como Long Dim FileX como Interger Winsock3.LocalPort 10000 Winsock3.RemoteHost 211.233.70.51 Winsock3.RemotePort 9500 FileX FreeFile Abrir App. Path udp1.dat para Binário como FileX X 1 Até Até X FileLen (App. Path udp1.dat) 1 Obter FileX. X, ByteX Winsock3.SendData ByteX X X 1 Loop Fechar arquivoX Quando envio dados dessa forma, ele envia 52 pacotes contendo 1 byte cada vez em vez de 1 pacote contendo 52 bytes. Este código funciona corretamente para o protocolo TCP, mas o UDP não funciona da mesma maneira. Como posso enviar dados binários usando o protocolo UDP que enviará apenas 1 pacote de dados. Estou fazendo um programa cliente que exige que dados binários sejam enviados para o servidor através do protocolo UDP. (Estou usando o controle winsock):: Eu tenho usado o seguinte código. :: Dim ByteX como Byte: Dim X como Long: Dim FileX como Interger:: Winsock3.LocalPort 10000: Winsock3.RemoteHost 211.233.70.51: Winsock3.RemotePort 9500:: FileX FreeFile: Abra o App. Path udp1.dat para Binário como FileX : X 1: Faça até X FileLen (App. Path udp1.dat) 1: Obter FileX. X, ByteX: Winsock3.SendData ByteX: X X 1: Loop: Fechar FileX:: Quando envio dados dessa forma, ele envia 52 pacotes contendo 1 byte em vez de 1 pacote contendo 52 bytes. Este código funciona corretamente para o protocolo TCP, mas o UDP não funciona da mesma maneira. Como posso enviar dados binários usando o protocolo UDP que enviará apenas 1 pacote de dados: Oi Experimente este protocolo Winsock3.Protocol sckUDPProtocol O Winsock tem sckTCPProtocol por padrão ... purpleDont levar a vida muito a sério, de qualquer forma, você não vai escapar vivo com isso usando dados binários usando winsock Im Desculpe, você está dizendo que eu tenho que usar Datagram em vez de Stream Sockets para ter esse trabalho que estou usando SOCKSTREAM neste momento, e eu preferiria ficar com ele. Existe alguma maneira de conseguir isso para aceitar o 0x00 e aceitar dados depois, enquanto ainda usa sockets de fluxo. Mais uma vez, obrigado por toda sua ajuda. Mikyu Hmm, isso é estranho. Eu pensei que o argumento SOCKDGRAM deveria especificar dados binários, em oposição a SOCKSTREAM. : O recv deve ler além de zero no caso. : Tem certeza de que não está capturando os dados em um tipo de tipo de seqüência de caracteres que você está imprimindo ou escrevendo para um arquivo ou algo com uma das rotinas de str: Quero dizer, você tem certeza de que está exibindo os dados recebidos corretamente Desculpe, você está dizendo que eu tenho que usar Datagram em vez de Stream Sockets para ter esse trabalho que estou usando SOCKSTREAM neste momento, e eu preferiria ficar com ele. Existe alguma maneira de conseguir isso para aceitar o 0x00 e aceitar dados depois, enquanto ainda usa sockets de fluxo. Mais uma vez, obrigado por toda sua ajuda. : Mikyu:. Hmm, isso é estranho. Eu pensei que o argumento SOCKDGRAM deveria especificar dados binários, em oposição a SOCKSTREAM. . O recv deve ler além de zero no caso. . Tem certeza de que não está capturando os dados em um tipo de dados de string que você está imprimindo ou escrevendo para um arquivo ou algo com uma das rotinas de str. Quero dizer, você tem certeza de que está exibindo os dados recebidos corretamente: SOCKDGRAM não significa dados binários. Isso significa que você deseja usar o protocolo UDP para enviar dados e os dados são enviados nos datagramas. SOCKSTREAM significa que você deseja usar o protocolo TCP e enviar dados como fluxo. Socket não se importa com o tipo de dados que você está enviando. Tudo o que você precisa é ponteiro para o buffer que contém os dados e o comprimento desse buffer. Zero dentro de dados não significa nada, é apenas zero. Os dados não são encerrados por zero como C-strings são. Socket não se preocupa com o conteúdo dos dados. Eu acho que há algo de errado com você receber o código. Talvez você esteja usando zero como terminador lá, o que é coisa muito ruim. Se você pudesse publicar o código que recebe dados aqui, eu poderia tentar descobrir o que estava errado com ele. Aqui está o código que estou usando. Mais uma vez, eu sou novo no winsock, então, fique comigo. Obrigado código int servidor (void) unsigned char recmsg3072 SOCKET serverfd, clientfd ouvir no sockfd, nova conexão no newfd SOCKADDRIN serveraddr SOCKADDRIN clientaddr int len ​​int j int msgsize 0 char pergunta WSADATA wsadata unsigned short verrequest FILE mike LINGER LingVar verrequest MAKEWORD (2,2 ) Se (WSAStartup (verrequest, ampwsadata) -1) printf (Não foi possível encontrar uma DLL Winsock utilizável) sair (1) se ((socket serverfd (AFINET, SOCKSTREAM, 0)) -1) perror (LADO DO SERVIDOR: não pode abrir o soquete) LingVar. lonoff TRUE LingVar. llinger 0 se (setsockopt (serverfd, SOLSOCKET, SOOOBINLINE, (char FAR) ampLingVar, sizeof (LingVar)) -1) perror (SERVER SIDE: não pôde executar setsockopt) exit (1) serveraddr. sinfamily AFINET serveraddr. sinport htons (SERVERPORT) serveraddr. sinaddr. saddr htonl (INADDRANY) memset (amp (serveraddr. sinzero),, 8) if (bind (serverfd, (struct sockaddr) ampserveraddr, sizeof (serveraddr)) -1) perror (SERVER SIDE: não pode ligar a porta) exit (1) if (listen (serverfd, PACKETQUEUE) -1) por Ror (SÉRIE DO SERVIDOR: não pode ouvir soquete) sair (1) memset (recmsg, 0x0, 3072) enquanto (1) printf (Você quer continuar (YN)) pergunta getchar () se (pergunta) pergunta getchar () if (Pergunta N pergunta n) retornar 0 printf (SERVER SIDE: Waiting for Data na porta) len sizeof (clientaddr) clientfd accept (serverfd, (struct sockaddr) ampclientaddr, amplen) if (clientfd -1) perror (SERVER SIDE: não pode aceitar Conexão) return ERROR printf (SERVER SIDE: conexão recebida de: s, inetntoa (clientaddr. sinaddr)) msgsize readline (recmsg, clientfd, clientaddr) se (MSgsize ERROR) printf (SERVER SIDE: Não foi possível ler a mensagem) coutltltthis é o tamanho da mensagem : Ltltmsgsizeltltendl fwrite (recmsg, sizeof (short int), 10, mike) para (j0 jlt10 j) printf (- c, recmsgj) closesocket (clientfd) se (WSACleanup () -1) perror (Problema com WSACLEANUP) sair ( 1) int readline (signignet char buf, SOCKET sd, SOCKADDRIN clientaddr) char segMAXDATA int offset 0 int res 1 int cliLen memset (seg, 0x0, MAXDATA) cliL (Tamanho do servidor (clientaddr) enquanto que ((res recvfrom (sd, seg, MAXDATA, 0, (struct sockaddr) ampclientaddr, ampcliLen)) SOCKETERROR) se (resEOFresWSAECONNRESETresWSAECONNABORTED) 0 outro lado terminated conn printf (conexão terminada pelo cliente) return offset memcpy (bufoffset, Seg, res) offset res memset (seg, 0x0, MAXDATA) retorna o código ERROR: SOCKDGRAM não significa dados binários. Isso significa que você deseja usar o protocolo UDP para enviar dados e os dados são enviados nos datagramas. SOCKSTREAM significa que você deseja usar o protocolo TCP e enviar dados como fluxo. :: Socket não se importa com o tipo de dados que você está enviando. Tudo o que você precisa é ponteiro para o buffer que contém os dados e o comprimento desse buffer. :: O zero de dados internos não significa nada, é apenas zero. Os dados não são encerrados por zero como C-strings são. Socket não se preocupa com o conteúdo dos dados. :: Eu acho que há algo de errado com você receber o código. Talvez você esteja usando zero como terminador lá, o que é coisa muito ruim. Se você pudesse publicar o código que recebe dados aqui, eu poderia tentar descobrir o que estava errado com ele. : Uma introdução ao Windows Socket Programming with C O que temos neste capítulo 1 parte 4 Data Transmission send () e WSASend () WSASendDisconnect () Dados fora da banda recv () e WSARecv () WSARecvDisconnect () Stream Protocols Scatter - Gather IO Breaking Connection Shutdown () closesocket () TCP ReceiverServer Com select () Exemplo de envio de transmissão de dados () e WSASend () WSASendDisconnect () Dados fora da banda recv () e WSARecv () A solicitação de recebimento será concluída somente Quando ocorre um dos seguintes eventos: o buffer fornecido pelo chamador está completamente cheio. A conexão foi fechada. O pedido foi cancelado ou ocorreu um erro. Observe que, se o transporte subjacente não suportar MSGWAITALL, ou se o soquete estiver em modo não bloqueador, essa chamada falhará com WSAEOPNOTSUPP. Além disso, se MSGWAITALL for especificado juntamente com MSGOOB, MSGPEEK ou MSGPARTIAL, essa chamada falhará com WSAEOPNOTSUPP. Este sinalizador não é suportado em sockets de datagramas ou em soquetes de CO orientados para mensagens. Claro, 0 não especifica ações especiais. O MSGPEEK faz com que os dados disponíveis para serem copiados para o buffer de recebimento fornecido. Mas esses dados não são removidos do buffer de sistemas. O número de bytes pendentes também é retornado. A inspeção de mensagens é ruim. Não só degrada o desempenho, como agora você precisa fazer duas chamadas de sistema (uma para espiar e outra sem o sinalizador MSGPEEK para realmente remover os dados), mas também não é confiável em determinadas circunstâncias. Os dados retornados podem não refletir a quantidade total disponível. Além disso, ao deixar dados nos buffers do sistema, o sistema tem menos espaço para conter dados recebidos. Como resultado, o sistema reduz o tamanho da janela TCP para todos os remetentes. Isso impede que seu aplicativo alcance o rendimento máximo possível. A melhor coisa a fazer é copiar todos os dados que você pode em seu próprio buffer e manipulá-lo lá. Existem algumas considerações ao usar recv () em um socket baseado em mensagem ou datagrama, como o UDP, que descreveremos mais tarde. Se os dados pendentes forem maiores do que o buffer fornecido, o buffer é preenchido com a quantidade de dados que ele irá conter. Nesse caso, a chamada recv () gera o erro WSAEMSGSIZE. Observe que o erro de tamanho da mensagem ocorre com os protocolos orientados para mensagens. Transfira protocolos como dados de entrada do buffer TCP e retornará tantos dados como os pedidos do aplicativo, mesmo que a quantidade de dados pendentes seja maior. Assim, para protocolos de transmissão você não encontrará o erro WSAEMSGSIZE. A função WSARecv () adiciona novas capacidades sobre recv (), como IO sobreposta e notificações de datagramas parciais. A definição de WSARecv () é: o parâmetro s é o soquete conectado. O segundo e terceiro parâmetros são os buffers para receber os dados. O parâmetro lpBuffers é uma matriz de estruturas WSABUF e dwBufferCount indica o número de estruturas WSABUF na matriz. O parâmetro lpNumberOfBytesReceived aponta para o número de bytes recebidos por esta chamada se a operação de recebimento for concluída imediatamente. O parâmetro lpFlags pode ser um dos valores MSGPEEK, MSGOOB ou MSGPARTIAL, ou uma combinação OR bit a bit desses valores. A bandeira MSGPARTIAL tem vários significados diferentes, dependendo de onde ele é usado ou encontrado. Para protocolos orientados a mensagens que suportam mensagens parciais (como o AppleTalk), esta bandeira é definida após o retorno de WSARecv () (se a mensagem inteira não puder ser retornada nesta chamada devido ao espaço de buffer insuficiente). Nesse caso, as chamadas subseqüentes de WSARecv () definem esta bandeira até que a mensagem inteira seja retornada, quando o sinalizador MSGPARTIAL for apagado. Se esse sinalizador for passado como um parâmetro de entrada, a operação de recepção deve ser concluída assim que os dados estiverem disponíveis, mesmo que seja apenas uma parte da mensagem inteira. O sinalizador MSGPARTIAL é usado apenas com protocolos orientados a mensagens, não com os de transmissão. Além disso, nem todos os protocolos suportam mensagens parciais. A entrada de protocolo para cada protocolo contém um sinalizador que indica se ele é compatível com esse recurso. Os parâmetros lpOverlapped e lpCompletionRoutine são usados ​​em operações IO sobrepostas, discutidas em outro capítulo. Existe uma outra função de recepção especializada que você deve estar ciente de: WSARecvDisconnect (). WSARecvDisconnect () Esta função é o oposto do WSASendDisconnect () e é definido da seguinte forma: int WSARecvDisconnect (SOCKET s, LPWSABUF lpInboundDisconnectData) Como a contrapartida de envio, os parâmetros do WSASendDisconnect () são o identificador de soquete conectado e uma estrutura WSABUF válida com o Dados a serem recebidos. Os dados recebidos podem ser apenas desconectando dados enviados por um WSASendDisconnect () no outro lado, ele não pode ser usado para receber dados normais. Além disso, uma vez que os dados são recebidos, esta função desativa a recepção da parte remota, o que equivale a chamar a função shutdown () (que é descrita mais tarde) com SDRECEIVE. Protocolos de fluxo Como a maioria das comunicações orientadas para conexão, como TCP, são protocolos de transmissão, descreva-os brevemente aqui. Um protocolo de transmissão é aquele que o remetente e o receptor podem dividir ou coagir dados em grupos menores ou maiores. A figura a seguir descreve brevemente o fluxo de pacotes TCP entre os lados do cliente e do servidor. A principal coisa a ter em conta com qualquer função que envia ou recebe dados em um soquete de fluxo é que você não está garantido para ler ou escrever a quantidade de dados que você solicita. Digamos que você tenha um buffer de caracteres com 2048 bytes de dados que deseja enviar com a função de envio. O código para enviar isto é: int nBytes 2048 Preencha o envio com 2048 bytes de dados Suponha que s é um soquete de fluxo conectado válido e conectado enviando (s, sendbuff, nBytes, 0) É possível enviar para retornar tendo enviado menos de 2048 bytes . A variável ret será definida para o número de bytes enviados porque o sistema aloca uma certa quantidade de espaço de buffer para cada socket para enviar e receber dados. No caso de enviar dados, os buffers internos mantêm os dados a serem enviados até que os dados possam ser colocados no fio. Várias situações comuns podem causar isso. Por exemplo, simplesmente transmitir uma enorme quantidade de dados fará com que esses buffers sejam preenchidos rapidamente. Além disso, para o TCPIP, existe o que é conhecido como o tamanho da janela (demonstração da janela deslizante). A extremidade de recepção ajustará esse tamanho de janela para indicar a quantidade de dados que pode receber. Se o receptor estiver inundado com dados, pode configurar o tamanho da janela para 0 para recuperar o atraso nos dados pendentes. Isso forçará o remetente a parar até receber um novo tamanho de janela maior do que 0. No caso de nossa chamada de envio, pode haver espaço de buffer para armazenar apenas 1024 bytes, caso em que você deve reenviar os 1024 bytes restantes. O código a seguir garante que todos os seus bytes sejam enviados: int nBytes 2048, nLeft, idx Remova o envio com 2048 bytes de dados enquanto (nLeft gt 0) Suponha que s é um soquete de fluxo conectado válido. As coisas ficam um pouco complicadas se o tamanho da sua mensagem variar . É necessário impor seu próprio protocolo para que o receptor saiba quão grande será a próxima mensagem. Por exemplo, os quatro primeiros bytes gravados no receptor serão sempre o tamanho inteiro em bytes da próxima mensagem. O receptor iniciará todas as leituras, observando os quatro primeiros bytes, convertendo-os em um inteiro e determinando quantos bytes adicionais incluirão essa mensagem. O suporte Scatter-Gather IO Scatter-gather é um conceito originalmente introduzido em Berkeley Sockets com as funções recv e writev. Esta funcionalidade está disponível com as funções Wassock 2 WSARecv (), WSARecvFrom (), WSASend () e WSASendTo (). É muito útil para aplicativos que enviam e recebem dados formatados de forma muito específica. Por exemplo, as mensagens de um cliente para um servidor podem ser sempre compostas por um cabeçalho fixo de 32 bytes especificando alguma operação, seguido por um bloco de dados de 64 bytes e terminado com um trailer de 16 bytes. Neste exemplo, WSASend () pode ser chamado com uma matriz de três estruturas WSABUF, cada uma correspondente aos três tipos de mensagem. Na extremidade receptora, WSARecv () é chamado com três estruturas WSABUF, cada uma contendo buffers de dados de 32 bytes, 64 bytes e 16 bytes. Ao usar sockets baseados em fluxo, as operações de dispersão e coleta simplesmente tratam os buffers de dados fornecidos nas estruturas WSABUF como um buffer contíguo. Além disso, a chamada de recepção pode retornar antes que todos os buffers estejam cheios. Nos soquetes baseados em mensagens, cada chamada para uma operação de recepção recebe uma única mensagem até o tamanho do buffer fornecido. Se o espaço de buffer for insuficiente, a chamada falhará com WSAEMSGSIZE e os dados serão truncados para se ajustarem ao espaço disponível. Claro, com protocolos que suportam mensagens parciais, o sinalizador MSGPARTIAL pode ser usado para evitar a perda de dados. Partindo a conexão Depois de terminar uma conexão de soquete, você deve fechá-la e liberar todos os recursos associados a esse identificador de soquete. Para realmente liberar os recursos associados a um identificador de soquete aberto, use a chamada closesocket (). Esteja ciente, no entanto, de que closesocket () pode ter alguns efeitos adversos, dependendo de como é chamado, que pode levar à perda de dados. Por este motivo, uma conexão deve ser terminada graciosamente com a função shutdown () antes de uma chamada para a função closesocket (). Estas duas funções da API são discutidas a seguir. Desligamento () Para garantir que todos os dados enviados por um aplicativo sejam recebidos pelo interlocutor, um aplicativo bem escrito deve notificar o destinatário de que não serão enviados mais dados. Do mesmo modo, os pares devem fazer o mesmo. Isso é conhecido como um fechamento gracioso e é executado pela função shutdown (), definida como: shutdown int (SOCKET s, int how) O parâmetro como pode ser SDRECEIVE, SDSEND ou SDBOTH. Para SDRECEIVE, as chamadas subseqüentes para qualquer função de recebimento no soquete são desativadas. Isso não tem efeito nas camadas de protocolo mais baixas. E para sockets TCP, se os dados estiverem em fila para receber ou se os dados chegarem subsequentemente, a conexão será redefinida. No entanto, em dados de entrada de soquetes UDP ainda é aceito e enfileirado (porque o desligamento () não tem significado para protocolos sem conexão). Para SDSEND, as chamadas subseqüentes para qualquer função de envio não são permitidas. Para sockets TCP, isso faz com que um pacote FIN seja gerado depois que todos os dados são enviados e reconhecidos pelo receptor. Finalmente, especificando SDBOTH desativa ambos envia e recebe. Observe que nem todos os protocolos orientados a conexão suportam o encerramento gracioso, que é o que a API de desligamento () é executada. Para esses protocolos (como ATM), somente closesocket () precisa ser chamado para encerrar a sessão. Uma bandeira que descreve quais tipos de operação estão resumidos na tabela a seguir. Os valores possíveis para este sinalizador estão listados no arquivo de cabeçalho Winsock2.h. Uma vez que a função shutdown () é chamada para desativar envio, receber ou ambos, não há nenhum método para reativar enviar ou receber para a conexão de soquete existente. Um aplicativo não deve confiar em ser capaz de reutilizar um soquete depois que ele foi desligado. Em particular, um provedor Windows Sockets não é necessário para suportar o uso de connect () em um soquete que foi encerrado. Se um aplicativo quiser reutilizar um soquete, a função DisconnectEx () deve ser chamada com o parâmetro dwFlags configurado para TFREUSESOCKET para fechar uma conexão em um soquete e preparar o identificador de soquete para ser reutilizado. Quando a solicitação DisconnectEx () for concluída, o identificador de soquete pode ser passado para a função AcceptEx () ou ConnectEx (). Se um aplicativo quiser reutilizar um soquete, as funções TransmitFile () ou TransmitPackets () podem ser chamadas com o conjunto de parâmetros dwFlags com TFDISCONNECT e TFREUSESOCKET para desligar depois de todos os dados terem sido enfileirados para transmissão e preparar o identificador de soquete para serem reutilizados. Quando a solicitação TransmitFile () for concluída, o identificador de soquete pode ser passado para a chamada de função usada anteriormente para estabelecer a conexão, como, por exemplo, AcceptEx () ou ConnectEx (). When the TransmitPackets() function completes, the socket handle can be passed to the AcceptEx() function. Take note that the socket level disconnect is subject to the behavior of the underlying transport. For example, a TCP socket may be subject to the TCP TIMEWAIT state, causing the DisconnectEx(), TransmitFile(), or TransmitPackets() call to be delayed. closesocket() The closesocket() function closes a socket and is defined as: int closesocket (SOCKET s) If no error occurs, closesocket() returns zero. Otherwise, a value of SOCKETERROR is returned, and a specific error code can be retrieved by calling WSAGetLastError(). The socket is marked as nonblocking, but the lonoff member of the linger structure is set to non-zero and the llinger member of the linger structure is set to a nonzero timeout value. Calling closesocket() releases the socket descriptor and any further calls using the socket fail with WSAENOTSOCK. If there are no other references to this socket, all resources associated with the descriptor are released. This includes discarding any queued data. Pending synchronous calls issued by any thread in this process are canceled without posting any notification messages. Pending overlapped operations are also canceled. Any event, completion routine, or completion port that is associated with the overlapped operation is performed but will fail with the error WSAOPERATIONABORTED. In addition, one other factor influences the behavior of closesocket(): whether the socket option SOLINGER has been set. An application should always have a matching call to closesocket() for each successful call to socket to return any socket resources to the system. TCP ReceiverServer With select() Example 1. While in the Visual C IDE, click File menu gt Project sub menu to create a new project. 2. Select Win32 for the Project types: and Win32 Console Application for the Templates. Put the project and solution name. Adjust the project location if needed and click OK. 3. Click Next for the Win32 Application Wizard Overview page. We will remove all the unnecessary project items. 4. In the Application page, select Empty project for the Additional options. Leave others as given and click Finish. 5. Next, we need to add new source file. Click Project menu gt Add New Item sub menu or select the project folder in the Solution Explorer gt Select Add menu gt Select New Item sub menu. 6. Select C File (.cpp) for the Templates. Put the source file name and click Add. Although the extension is. cpp, Visual C IDE will recognize that the source code used is C based on the Compile as C Code (TC) option which will be set in the project property page later. 7. Now, add the source code as given below. A sample of the select() return value int recvTimeOutTCP(SOCKET socket, long sec, long usec)

No comments:

Post a Comment