Pergunta

Estou envio e recebimento de dados binários de / para um dispositivo em pacotes (64 byte). Os dados têm um formato específico, partes dos quais variam com diferentes pedido / resposta.

Agora eu estou projetando um intérprete para os dados recebidos. Basta ler os dados por posições é OK, mas não parece tão legal quando eu tenho uma dúzia de formatos de resposta diferentes. Atualmente, estou pensando em criar algumas estruturas para o efeito, mas eu não sei como ele vai com estofamento.

Talvez haja uma maneira melhor?


Relacionado:

Foi útil?

Solução

Já fiz isso inúmeras vezes antes: é um cenário muito comum. Há uma série de coisas que eu praticamente sempre fazer.

Não se preocupe muito sobre tornando-o mais eficiente disponível.

Se nós acabam gastando muito tempo embalagem e pacotes de desembalar, então podemos sempre alterá-lo para ser mais eficiente. Enquanto eu não encontrei um caso em que eu tive que até agora, eu não fui implementar roteadores de rede!

Enquanto usando structs / sindicatos é a abordagem mais eficiente em termos de tempo de execução, ele vem com uma série de complicações: convencer o seu compilador para embalar os structs / sindicatos para corresponder à estrutura octeto dos pacotes que você precisa, o trabalho para o alinhamento evitar e questões endianness, e uma falta de segurança, pois não existe ou pouca oportunidade de fazer checagens em compilações de depuração.

Muitas vezes eu acabar com uma arquitetura que inclui os seguintes tipos de coisas:

  • A classe base do pacote. Todos os campos de dados comuns são acessíveis (mas não modificável). Se os dados não são armazenados em um formato compactado, então há uma função virtual que irá produzir um pacote embalado.
  • Um número de classes de apresentação para tipos de pacotes específicos, derivado do tipo de pacote comum. Se estamos usando uma função de embalagem, em seguida, cada classe apresentação deve implementá-lo.
  • Qualquer coisa que pode ser inferida a partir do tipo específico da classe apresentação (ou seja, um pacote tipo id de um campo de dados comum), é tratada como parte da inicialização e é de outra maneira não modificável.
  • Cada classe apresentação pode ser construído a partir de um pacote descompactado, ou será graciosamente falhar se o de pacote de dados é inválido para o tipo. Este pode então ser embrulhado em uma fábrica por conveniência.
  • Se não temos RTTI disponível, podemos obter "RTTI do pobre homem" usando o ID de pacote para determinar qual classe apresentação específica de um objeto realmente é.

Em tudo isso, é possível (mesmo que apenas para compilações de depuração) para verificar se cada campo que é modificável está sendo definido para um valor sã. Embora possa parecer um monte de trabalho, torna-se muito difícil ter um pacote invalidamente formatada, um pré-embalados pacotes conteúdo pode ser easilly verificado por olho usando um depurador (uma vez que é tudo em variáveis ??formato de plataforma nativa normais).

Se nós temos que implementar um esquema de armazenamento mais eficiente, que também pode ser envolvido nesta abstração com pouco custo adicional de desempenho.

Outras dicas

Você precisa usar estruturas e ou sindicatos. Você precisa ter certeza de seus dados estão devidamente embalados em ambos os lados da conexão e você pode querer traduzir de e para rede byte ordem em cada extremidade se há alguma chance de que ambos os lados da conexão pode ser executado com um diferente endianess.

Como um exemplo:

#pragma pack(push)  /* push current alignment to stack */
#pragma pack(1)     /* set alignment to 1 byte boundary */
typedef struct {
    unsigned int    packetID;  // identifies packet in one direction
    unsigned int    data_length;
    char            receipt_flag;  // indicates to ack packet or keep sending packet till acked
    char            data[]; // this is typically ascii string data w/ \n terminated fields but could also be binary
} tPacketBuffer ;
#pragma pack(pop)   /* restore original alignment from stack */

e, em seguida, ao atribuir:

packetBuffer.packetID = htonl(123456);

e, em seguida, ao receber:

packetBuffer.packetID = ntohl(packetBuffer.packetID);

Aqui estão algumas discussões sobre Endianness e Alinhamento e embalagem Estrutura

Se você não arrumar a estrutura que vai acabar alinhados com limites de palavra eo layout interno da estrutura e do tamanho será incorreta.

É difícil dizer o que a melhor solução é sem conhecer o formato exato (s) dos dados. Você já pensou em usar sindicatos?

Eu concordo com Wuggy. Você também pode usar a geração de código para fazer isso. Use um arquivo de definição de dados simples de definir todos os seus tipos de pacotes, em seguida, executar um script python sobre ele para gerar estruturas do protótipo e serialiation / funções desserialização para cada um.

Esta é uma solução "out-of-the-box", mas eu sugiro dar uma olhada no Python construir biblioteca.

Construct é uma biblioteca python para análise e construção de dados estruturas (binários ou de texto). Isto é com base no conceito da definição de dados estruturas em forma declarativa, ao invés de código de procedimento: mais construes complexas são compostas de um Hierarquia das mais simples. É o primeira biblioteca que faz a análise de diversão, em vez da habitual dor de cabeça é hoje.

construção é muito robusto e poderoso, e apenas ler o tutorial irá ajudá-lo a entender melhor o problema. O autor também tem planos para código de auto-geração C a partir de definições, por isso é definitivamente vale a pena o esforço para ler sobre.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top