Empacotamento de dados eficiente para uma rede cliente-servidor

8

Idioma: C ++

Minha pergunta é a seguinte: Gostaria de saber qual seria a melhor ou pelo menos uma boa maneira de compactar e enviar dados do cliente para o servidor e o inverso. Haverá alguns dados compondo um único pacote. Um pacote terá um "id", que define para que serve, então os dados em uma ordem predeterminada para a "ação" à qual o pacote corresponde.

Para sistemas menos dependentes de desempenho, eu apenas enviava seqüências de caracteres, que seriam separadas por um espaço, sendo eles os dados da "ação" e a primeira "palavra" do identificador de pacotes e apenas encadeava as instruções if verificando quando há uma correspondência .

Agora, para um sistema mais crítico, o que eu pensei até agora foi algo como isto:

Faça uma string com a identificação do pacote e os dados e envie-os. Em seguida, para descompactar, eu poderia extrair o primeiro número inteiro na string e ter uma matriz de manipuladores de pacotes, com índices correspondentes ao ID do pacote que eles manipulam, e fazer algo como packetHandlers [packetID] .Process (packetData).

O que você acha disso, alguma sugestão? muito apreciado!

Grimshaw
fonte

Respostas:

10

Primeiro, confirme que você realmente precisa de um protocolo sofisticado e eficiente antes de desperdiçar recursos para desenvolvê-lo. Não se esqueça de depurar / modificar seu jogo será mais difícil e demorado devido ao seu protocolo sofisticado. Gostaria apenas de abstrair a comunicação de rede, para que a implementação real possa ser facilmente trocada por uma mais eficiente, se necessário no futuro. Use o protocolo mais simples possível até encontrar problemas de desempenho. Outra vantagem de projetar seu protocolo posteriormente é que ele pode ser otimizado para dados reais transportados versus o que você prevê que será transportado.

Depois de confirmar que você precisa de um protocolo sofisticado, observe os protocolos que outras pessoas gastaram um tempo considerável desenvolvendo. Alguns exemplos:

  • (atualização) O desenvolvedor original do Protocol Buffers (v2) desenvolveu um novo protocolo chamado Cap'n Proto. Ele explica suas decisões de design e se compara a outras bibliotecas semelhantes lançadas recentemente: Cap'n Proto, FlatBuffers e SBE .
  • O principal gargalo do Google é a comunicação em rede entre computadores, portanto, eles provavelmente consideraram a eficiência no desenvolvimento de Buffers de Protocolo . Manipula graciosamente a compatibilidade com versões anteriores / anteriores ( quando você decide alterar suas estruturas de dados). Usado por todos os principais produtos do Google (Gmail, Pesquisa etc.)
  • O Apache Thrift é um protocolo semelhante usado pelo Facebook.
  • RakNet é uma biblioteca de rede de código aberto projetada especificamente para o desenvolvimento de jogos.
  • O ZoidCom é outra biblioteca de rede voltada para o desenvolvimento de jogos. Não é de código aberto, mas você ainda pode estudá-lo para obter dicas de design.

A primeira regra de otimização de programa: não faça isso.
A Segunda Regra da Otimização de Programas (somente para especialistas!): Não faça isso ainda.

[ Michael A. Jackson ]

Em outras palavras: seu parâmetro de otimização primário deve ser: vida (anos de vida por implementação do programa). [ Como programar jogos independentes. Slide 21. Jonathan Blow. ]

Leftium
fonte
11
bom homem de leitura! muito obrigado pela resposta completa, com certeza ajudou, e estou seguindo seu conselho inteiramente, apenas o abstrato esta, tornando simples o suficiente para agora :)
Grimshaw
Certamente que o caso de uso do Google para buffers de protocolo não era eficiência no sentido padrão, mas para maximizar a compatibilidade entre todas as plataformas possíveis e quaisquer futuras versões de dados (que é eficiência sob outra perspectiva). Estarei aqui lendo suas outras anotações, uma coleção muito legal para eu me familiarizar com o assunto.
Patrick Hughes
O RakNet não é de código aberto.
Gerstmann
@ Gerstmann: Raknet é código-fonte aberto (mais uma vez): github.com/OculusVR/RakNet
Leftium 07/07/14
0

Por que usar dois esquemas de codificação diferentes? Basta usar o segundo para cada sistema. Apenas mantenha as coisas simples.
Considere usar a compactação delta. Ou seja, envie um valor total e depois disso apenas as coisas que mudaram. Após algumas iterações do jogo, envie um valor total novamente.
Outra codificação que você pode considerar é a Base 128 Varint. O Google Protobufs o usa. Dê uma olhada na página "Codificação" do guia do desenvolvedor: Codificação de buffers de protocolo Pode economizar alguns bytes.

Lurca
fonte
O primeiro sistema de que falei foi um mero exemplo de outros projetos :) Eu certamente gostei da idéia de compressão delta, obrigado, companheiro!
Grimshaw
0

O que pode ser um exemplo dos dados que você está enviando? Não vejo motivo para fazer algo excessivamente chique. Depois que os dados estiverem totalmente carregados no buffer do receptor, inspecione o primeiro com intbase em seu valor, e você saberá como processar o restante dos dados.

Assim, um pacote que tem quatro partes de dados id, val1, val2, e val2pode ter esta aparência:

// I'm using words (one byte) so my sample data is short
00000001 00101000 00010110 00010100 

Ao ler o primeiro byte (que você sabe que sempre estará lá), você decide como processar o próximo conjunto de dados. Se a primeira palavra (id) é que 00000001você sabe que existem mais três dwords a seguir, e esse é o fim do pacote. Para continuar o exemplo, você pode ter id = 00000010e sua especificação diz que para o valor id 2, você processa float, float, floatnessa ordem, o que pode especificar uma posição do jogador no espaço do mundo.

Pense nisso ao escrever seu próprio sistema de arquivos binários, você tem um valor de cabeçalho, que descreve o restante dos dados, onde eles estão localizados (em que posição) e que tipo de dados devem ser tratados.

Nate
fonte
Entendi, a única questão que me resta é: está empacotando todas essas entradas e flutuações em uma string padrão o suficiente, ou devo usar tipos de dados mais leves?
Grimshaw 21/07
Como dito por outros, comece com a corda e veja o que acontece. Provavelmente, você terá um gargalo em outra parte do seu código.
Nate