Questões de design - envio de segmentos de dados pequeno sobre TCP com Winsock

Traduções deste artigo Traduções deste artigo
ID do artigo: 214397
Expandir tudo | Recolher tudo

Neste artigo

Sumário

Quando você precisar enviar pacotes de dados pequeno sobre TCP, o design do seu aplicativo Winsock é especialmente crítico. Um design que não leva em conta a interação de confirmação atrasada, o algoritmo de Nagle e Winsock buffer pode afetar drasticamente a velocidade. Este artigo discute esses problemas, usando alguns estudos de casos e deriva de uma série de recomendações para o envio de pacotes de dados pequeno com eficiência de um aplicativo Winsock.

Mais Informações

Plano de fundo

Quando uma pilha Microsoft TCP recebe um pacote de dados, um temporizador de retardo de 200 ms é desativada. Quando uma confirmação é enviada no final, o cronômetro de atraso é redefinido e iniciará outra atraso de 200 ms quando o próximo pacote de dados é recebido. Para aumentar a eficiência na Internet e os aplicativos de intranet, a pilha TCP da Microsoft usa os seguintes critérios para decidir quando enviar um ACK em pacotes de dados recebidos:
  • Se o segundo pacote de dados for recebido antes que expire o timer de atraso, uma confirmação é enviada.
  • Se houver dados a serem enviados na mesma direção como uma confirmação antes do segundo pacote de dados é recebido e o delay timer expira, a confirmação é piggybacked com o segmento de dados e enviada imediatamente.
  • Quando o temporizador de retardo expirar, uma confirmação é enviada.
Para evitar ter pacotes de dados pequeno congestionar a rede, pilha TCP da Microsoft permite que o algoritmo de Nagle por padrão, que mescla um buffer de dados pequeno de várias chamadas de envio e atrasos de envio até que um ACK para o pacote de dados anterior enviado é recebido do host remoto. Estas são as duas exceções para o algoritmo Nagle:
  • Se a pilha tiver unidas um buffer de dados maior que a unidade de transmissão máxima (MTU), um pacote em tamanho normal é enviado imediatamente sem aguardar a confirmação do host remoto. Em uma rede Ethernet, o MTU para TCP/IP é 1460 bytes.
  • A opção de soquete TCP_NODELAY é aplicada para desativar o algoritmo Nagle para que os pacotes de dados pequenos são entregues com o host remoto sem atraso.
Para otimizar o desempenho na camada de aplicativo, o Winsock buffers de dados de cópias do aplicativo enviam chamadas para um buffer de kernel do Winsock. Em seguida, a pilha usa seu próprio heurística (por exemplo, o algoritmo de Nagle) para determinar quando, na verdade, coloque o pacote na conexão. Você pode alterar a quantidade de Winsock kernel buffer alocado para o soquete usando a opção SO_SNDBUF (é 8K por padrão). Se necessário, o Winsock pode buffer significativamente mais do que o SO_SNDBUF tamanho do buffer. Na maioria dos casos, a conclusão do envio do aplicativo indica somente o buffer de dados em um aplicativo enviar chamada é copiada para o buffer de Winsock kernel e não indica que os dados atingiu o meio de rede. A única exceção é quando você desativar o armazenamento de Winsock definindo SO_SNDBUF como 0.

Winsock usa as seguintes regras para indicar a conclusão do envio para o aplicativo (dependendo de como o envio é chamado, a notificação de conclusão pode ser a função de retorno de uma chamada de bloqueio, sinalização de um evento ou chamar uma função de notificação e assim por diante):
  • Se o soquete esteja ainda na cota SO_SNDBUF, o Winsock copia os dados de envio do aplicativo e indica a conclusão do envio para o aplicativo.
  • Se o soquete está além da cota SO_SNDBUF e há somente um envio anteriormente armazenados em buffer ainda no buffer de pilha de kernel, o Winsock copia os dados de envio do aplicativo e indica a conclusão do envio para o aplicativo.
  • Se o soquete está além da cota SO_SNDBUF e não há mais de um buffer anteriormente enviar no buffer de pilha de kernel, o Winsock copia os dados de envio do aplicativo. Winsock não indica a conclusão do envio para o aplicativo até que a pilha seja concluída suficiente envia para colocar o soquete de volta dentro de cota SO_SNDBUF ou apenas uma condição de envio pendente.

Estudo de caso 1

Visão geral:

Um cliente TCP Winsock precisa enviar 10000 registros em um servidor TCP Winsock para armazenar em um banco de dados. O tamanho dos registros varia de 20 bytes para 100 bytes de comprimento. Para simplificar a lógica do aplicativo, o design é:
  • O cliente faz apenas enviar bloqueio. O servidor faz apenas recv bloqueio.
  • O soquete do cliente define o SO_SNDBUF como 0 para que cada registro sai em um segmento de dados único.
  • O recebimento de chamadas do servidor em um loop. O buffer lançado no recv é 200 bytes para que cada registro pode ser recebido em uma receber chamada.

Desempenho:

Durante os testes, o desenvolvedor localiza que o cliente só pode enviar cinco registros por segundo para o servidor. O total de 10000 registros, máximo na 976K bytes de dados (10000 * 100 / 1024), leva mais de meia hora para enviar para o servidor.

Análise:

Como o cliente não define a opção TCP_NODELAY, o algoritmo Nagle força a pilha TCP para aguardar uma confirmação antes de enviar outro pacote na conexão. No entanto, o cliente desabilitou o buffer de Winsock, definindo a opção SO_SNDBUF como 0. Portanto, o 10000 enviar chamadas precisam ser enviados e ACK'ed individualmente. Cada ACK é atrasadas 200-ms, pois este processo ocorre na pilha TCP do servidor:
  • Quando o servidor recebe um pacote, o timer de atraso de 200 ms é desativada.
  • O servidor não precisa retornar nada, portanto, a confirmação não pode ser piggybacked.
  • O cliente não enviará outro pacote, a menos que o pacote anterior é confirmado.
  • O temporizador de retardo no servidor expira e uma confirmação é enviada de volta.

Como melhorar:

Há dois problemas com esse design. Em primeiro lugar, há o problema do temporizador de retardo. O cliente precisa ser capaz de enviar dois pacotes para o servidor em 200-Sra. porque o cliente usa o algoritmo de Nagle por padrão, ele deve usar apenas o armazenamento em buffer de Winsock padrão e não defina SO_SNDBUF como 0. Depois que a pilha TCP tem unidas um buffer maior que a unidade de transmissão máxima (MTU), um pacote em tamanho normal é enviado imediatamente sem aguardar a confirmação do host remoto.

Em segundo lugar, esse projeto chama um envio para cada registro de tal tamanho pequeno. Enviar esta pequena de um tamanho não é muito eficiente. Nesse caso, o desenvolvedor poderá preencher cada registro para 100 bytes e enviar 80 registros em vez de um cliente envia a chamada. Para permitir que o servidor sabe quantos registros serão enviados no total, o cliente poderá começar a comunicação com um cabeçalho de tamanho de correção que contém o número de registros a seguir.

Estudo de caso 2

Visão geral:

Um aplicativo de cliente TCP Winsock abre duas conexões com um aplicativo de servidor TCP Winsock fornecendo serviço de cotações de ações. A primeira conexão é usada como um canal de comando para enviar o símbolo de ação para o servidor. A segunda conexão é usada como um canal de dados para receber a cotação de ações. Após o estabelecimento de duas conexões, o cliente envia um símbolo de ações para o servidor por meio do canal de comando e aguarda até que a cotação de ações voltar o canal de dados. Ele envia a próxima solicitação de símbolo de ação para o servidor somente após a primeira cotação de ações foi recebida. O cliente e o servidor não defina a opção SO_SNDBUF e TCP_NODELAY.

Desempenho:

Durante os testes, o desenvolvedor localiza que o cliente pode obter apenas cinco cotações por segundo.

Análise:

Esse design permite apenas uma solicitação de cotação de ações pendentes de cada vez. O primeiro símbolo da ação é enviado para o servidor por meio do canal de comando (conexão) e uma resposta é enviada imediatamente do servidor para o cliente sobre o canal de dados (conexão). Em seguida, o cliente envia imediatamente a segunda solicitação de símbolo de ação e enviar imediatamente retorna como o buffer de solicitação na chamada de envio é copiado para o buffer de kernel do Winsock. No entanto, a pilha TCP do cliente não é possível enviar a solicitação de seu buffer de kernel imediatamente porque o primeiro enviar sobre o canal do comando não é confirmado ainda. Depois de 200-ms atrasam temporizador no canal de comando do servidor expira, a confirmação para a primeira solicitação de símbolo volta para o cliente. Em seguida, a segunda solicitação de cotação é enviada com êxito para o servidor após atrasadas para Sra. 200 que a cotação para o símbolo da ação segundo volta imediatamente por meio do canal de dados porque, nesse momento, o cronômetro de atraso no canal de dados do cliente expirou. Um pacote ACK para resposta de cotação anterior é recebido pelo servidor. (Lembre-se de que o cliente não pôde enviar uma segunda solicitação de cotação de ações para 200 ms, assim dando tempo para o temporizador de retardo no cliente para expirar e enviar um pacote ACK para o servidor.) Como resultado, o cliente obtém a segunda resposta de cotação e pode emitir outra solicitação de cotação, que está sujeito o mesmo ciclo.

Como melhorar:

O design de duas conexões (canal) aqui é desnecessário. Se você usar apenas uma conexão para a solicitação de cotação de ações e a resposta, a confirmação da solicitação de cotação pode ser piggybacked a resposta de cotação e voltar imediatamente. Para melhorar ainda mais o desempenho, o cliente pôde "multiplexação" várias solicitações de cotação de ações em uma chamada de envio para o servidor e o servidor pode também "multiplexação" várias respostas de cotação em uma chamada de envio ao cliente. Se o design de dois canais unidirecionais é realmente necessário por algum motivo, ambos os lados devem definir a opção TCP_NODELAY para que os pacotes pequenos podem ser enviados imediatamente sem ter de esperar por uma ACK para o pacote anterior.

Recomendações:

Enquanto esses dois estudos de caso são gerados, elas ajudam a ilustrar algumas piores cenários. Quando você cria um aplicativo que envolve o segmento de dados pequeno abrangentes envia e recvs, você deve considerar as seguintes diretrizes:
  • Se os segmentos são de dados não críticos, o aplicativo deve mesclá-los em um grande bloco de dados para passar para uma chamada de envio. Porque o buffer de envio é provavelmente a ser copiado para o buffer de kernel do Winsock, o buffer não deve ser muito grande. Um pouco menos de 8K é geralmente eficaz. Desde que o Winsock kernel obtém um bloco maior do que o MTU, ele enviará vários pacotes em tamanho normal e um último pacote com tudo o que resta. O lado de envio, exceto o último pacote, não será atingido pelo timer de atraso de 200 ms. O último pacote, se ele for um pacote ímpar, é ainda pode ser o algoritmo de confirmação de recebimento atrasado. Se a pilha do envio final obtém outro bloco maiores que o MTU, ele ainda pode ignorar o algoritmo de Nagle.
  • Se possível, evite conexões de soquete com o fluxo de dados unidirecional. Comunicações por soquetes unidirecionais são mais facilmente afetadas pelo Nagle e algoritmos de reconhecimento de atraso. Se a comunicação segue uma solicitação e um fluxo de resposta, você deve usar um único soquete fazer envia e recvs para que a confirmação pode ser piggybacked na resposta.
  • Se todos os segmentos de dados pequeno precisam ser enviados imediatamente, defina a opção TCP_NODELAY no lado do remetente.
  • A menos que você deseja garantir que um pacote é enviado na conexão quando a conclusão do envio é indicado pelo Winsock, você não deve definir o SO_SNDBUF a zero. Na verdade, o buffer de 8K padrão tiver sido determinado heuristicamente funcione bem para a maioria das situações, e você não deve alterá-la, a menos que você tenha testado que sua nova configuração de buffer do Winsock oferece desempenho melhor do que o padrão. Além disso, na maioria das vezes é vantajoso para aplicativos que em massa a transferência de dados definindo SO_SNDBUF como zero. Mesmo assim, para obter máxima eficiência deve usá-lo em conjunto com dupla buffer (mais de um envio pendente a qualquer momento) e sobrepostas e/s.
  • Se a entrega de dados não precisa ser garantida, usam UDP.

Referências

Para obter mais informações sobre a confirmação de recebimento atrasado e o algoritmo de Nagle, consulte o seguinte:

Braden, R. [1989], RFC 1122, requisitos de engenharia de Internet do Internet Hosts - camadas de comunicação, força tarefa.

Propriedades

ID do artigo: 214397 - Última revisão: sábado, 25 de maio de 2013 - Revisão: 4.0
Palavras-chave: 
kbdswnet2003swept kbapi kbinfo kbip kbnetwork kbwinsock kbmt KB214397 KbMtpt
Tradução automática
IMPORTANTE: Este artigo foi traduzido pelo software de tradução automática da Microsoft e eventualmente pode ter sido editado pela Microsoft Community através da tecnologia Community Translation Framework (CTF) ou por um tradutor profissional. A Microsoft oferece artigos traduzidos automaticamente por software, por tradutores profissionais e editados pela comunidade para que você tenha acesso a todos os artigos de nossa Base de Conhecimento em diversos idiomas. No entanto, um artigo traduzido pode conter erros de vocabulário, sintaxe e/ou gramática. A Microsoft não é responsável por qualquer inexatidão, erro ou dano causado por qualquer tradução imprecisa do conteúdo ou por seu uso pelos nossos clientes.
Clique aqui para ver a versão em Inglês deste artigo: 214397

Submeter comentários

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com