Pergunta

Eu estou lendo a partir de um fluxo de bytes que contém uma série de comprimento variável descritores que eu estou representando como várias estruturas/classes no meu código.Cada descritor tem um comprimento fixo de cabeçalho em comum com todos os outros descritores, que são utilizados para identificar o seu tipo.

Existe um modelo apropriado ou padrão que pode usar para melhor analisar e representar cada descritor e, em seguida, executar uma ação apropriada dependendo do tipo?

Foi útil?

Solução

Eu tenho escrito muitos desses tipos de analisador.

Eu recomendo que você leia o comprimento fixo de cabeçalho e, em seguida, envio para o correto construtor de suas estruturas de dados usando um simples switch-case, passando o cabeçalho fixo e fluxo para que o construtor para que ele possa consumir a parte variável do fluxo.

Outras dicas

Este é um problema comum na análise do arquivo.Geralmente, você lê a conhecido parte do descritor (que felizmente é de comprimento fixo neste caso, mas nem sempre), e ramo de lá.Geralmente eu uso uma padrão de estratégia de aqui, já que eu geralmente espera que o sistema seja amplamente flexível, mas sim a uma recta ou interruptor de fábrica podem funcionar bem.

A outra questão é:controlar e confiança a jusante código?Significado:a fábrica / estratégia de implementação?Se o fizer, então você pode apenas dar-lhes a sequência e o número de bytes que você espera que eles consomem (talvez colocar um pouco de depuração declarações no lugar, para verificar se eles fazer leia exatamente a quantidade certa).

Se você não pode de confiança fábrica/implementação da estratégia (talvez você permitir que o usuário-código para uso personalizado deserializers), então gostaria de construir um wrapper em cima do fluxo (exemplo: SubStream a partir de protobuf-net), que só permite que o esperado o número de bytes a ser consumido (relatório EOF depois), e não permite buscar/etc operações fora deste bloco.Eu também gostaria de ter verificações de tempo de execução (até mesmo nas compilações) de que um número suficiente de dados tem sido consumida, mas, neste caso, eu provavelmente apenas de leitura passado quaisquer dados não lidos - i.e.se esperávamos a jusante do código de consumir 20 bytes, mas apenas de leitura 12, em seguida, ignore a próxima 8 e leia o nosso próximo descritor.

Para expandir em que;uma estratégia de design aqui poderá ter algo do tipo:

interface ISerializer {
    object Deserialize(Stream source, int bytes);
    void Serialize(Stream destination, object value);
}

Você pode construir um dicionário (ou apenas uma lista se o número é pequeno) de tal serializadores por esperado marcadores, e resolver o seu serializador, em seguida, invocar o Deserialize o método.Se você não reconhece o marcador, em seguida, (ou um dos):

  • pular a determinado número de bytes
  • lançar um erro
  • armazenar o extra bytes em um buffer em algum lugar (permitindo a ida de dados inesperados)

Como um lado-nota acima esta abordagem (estratégia) é útil se o sistema é determinado em tempo de execução, através da reflexão, através de um tempo de execução de DSL (etc).Se o sistema é inteiramente previsível em tempo de compilação (porque ele não muda, ou porque você está usando de geração de código) e, em seguida, uma linha reta switch a abordagem pode ser mais apropriado - e você provavelmente não precisa extra interfaces, pois você pode injetar o código apropriado diretamente.

Uma coisa importante a se lembrar, se você está lendo a partir do fluxo e não detectar um cabeçalho válido/mensagem, jogue fora apenas o primeiro byte antes de tentar novamente.Muitas vezes eu vi um pacote inteiro ou mensagem de são jogados fora em vez disso, o que pode resultar em dados válidos sejam perdidas.

Isso soa como ele poderia ser um emprego para o Método De Fábrica ou, talvez, Resumo De Fábrica.Com base no cabeçalho você escolher qual o método de fábrica para chamar, e que retorna um objeto do tipo relevante.

Se este é melhor do que simplesmente adicionar construtores para uma instrução switch depende da complexidade e a uniformidade dos objetos que você está criando.

Gostaria de sugerir:

fifo = Fifo.new

while(fd is readable) {
  read everything off the fd and stick it into fifo
  if (the front of the fifo is has a valid header and 
      the fifo is big enough for payload) {

      dispatch constructor, remove bytes from fifo
  }
}

Com este método:

  • você pode fazer alguma verificação de erro para o mal cargas, e, potencialmente, lançar dados ruins de distância
  • dados não está aguardando a fd do buffer de leitura (que pode ser um problema para grandes cargas)

Se você gostaria que ele fosse bom OO, você pode usar o visitante padrão em uma hierarquia de objeto.Como eu fiz foi assim (para a identificação de pacotes capturados fora da rede, é praticamente a mesma coisa que você pode precisar):

  • grande hierarquia de objetos, com uma classe pai

  • cada classe tem um estático contructor que registra com seu pai, então o pai sabe sobre seus filhos diretos (este foi c++, eu acho que esse passo não é necessário em línguas com boa reflexão suporte)

  • cada classe tinha um construtor estático método que tem a parte restante do fluxo e com base em que, ele decidiu se for de sua responsabilidade para manipular os dados ou não

  • Quando um pacote veio, eu simplesmente passou ao construtor estático método de principal, de classe principal (chamado de Pacote), que por sua vez verificados todos os seus filhos se da sua responsabilidade para lidar com esse pacote, e isto passou-se recursivamente, até que uma classe na parte inferior da hierarquia voltou a classe instanciada de volta.

  • Cada um dos estático "construtor" métodos de cortar o seu próprio cabeçalho do fluxo e transmitida apenas a carga para seus filhos.

A vantagem desta abordagem é que você pode adicionar novos tipos em qualquer lugar na hierarquia do objeto SEM a necessidade de ver/alterar QUALQUER outra classe.Funcionou incrivelmente bem gostoso e para os pacotes;era assim:

  • Pacote
  • EthernetPacket
  • IPPacket
  • UDPPacket, TCPPacket, ICMPPacket
  • ...

Eu espero que você possa ver a ideia.

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