Pergunta

Isso é uma espécie de ramo do meu outra questão. Leia se quiser, mas não é necessário.

Basicamente, percebi que, para usar efetivamente o BEGNRECEIVO () de C#em mensagens grandes, preciso (a) ler o comprimento do pacote primeiro e depois ler exatamente que muitos bytes ou (b) usam um delimitador de ponta. Minha pergunta é: um desses presentes nos buffers de protocolo? Eu ainda não os usei, mas analisando a documentação, não parece que haja um cabeçalho de comprimento ou um delimitador.

Caso contrário, o que devo fazer? Devo apenas construir a mensagem e prefixá -la/sufixá -la com o cabeçalho do comprimento/delimitador EOP?

Foi útil?

Solução

Você precisa incluir o tamanho ou o marcador final em seu protocolo. Nada é incorporado em soquetes baseados em fluxo (TCP/IP), além de suportar um fluxo indefinido de octetos arbitrariamente divididos em pacotes separados (e os pacotes também podem ser derramados em trânsito).

Uma abordagem simples seria para cada "mensagem" ter um cabeçalho de tamanho fixo, incluir uma versão de protocolo e um tamanho de carga útil e quaisquer outros dados fixos. Em seguida, o conteúdo da mensagem (carga útil).

Opcionalmente, um rodapé de mensagem (tamanho fixo) pode ser adicionado com uma soma de verificação ou até mesmo uma assinatura criptográfica (dependendo dos seus requisitos de confiabilidade/segurança).

Saber o tamanho da carga útil permite que você continue lendo vários bytes que serão suficientes para o restante da mensagem (e se uma leitura concluir com menos, fazendo outra leitura para os bytes restantes até que toda a mensagem seja recebida).

Ter um indicador de mensagem final também funciona, mas você precisa definir como lidar com sua mensagem contendo a mesma sequência de octeto ...

Outras dicas

Desculpas por chegar tarde na festa. Eu sou o autor da Protobuf-Net, uma das implementações C#. Para o uso da rede, você deve considerar os métodos [de] serializeWithLengthPrefix" - dessa maneira, ele lidará automaticamente com os comprimentos para você. Existem exemplos na fonte.

Não vou entrar em grandes detalhes em um post antigo, mas se você quiser saber mais, adicione um comentário e eu voltarei a você.

Concordo com Matt que um cabeçalho é melhor do que um rodapé para buffers de protocolo, pelo principal motivo de que o PB é um protocolo binário, é problemático criar um rodapé que também não seria uma sequência de mensagens válida. Muitos protocolos baseados em rodapés (normalmente os EOL) funcionam porque o conteúdo da mensagem está em um intervalo definido (normalmente 0x20 - 0x7F ASCII).

Uma abordagem útil é ter seu código de nível mais baixo, basta ler os buffers fora do soquete e apresentá -los a uma camada de enquadramento que monta mensagens completas e lembra as parciais (apresento uma abordagem assíncrona a isso (usando o CCR) aqui, embora para um protocolo de linha).

Para consistência, você sempre pode definir sua mensagem como uma mensagem PB com três campos: um fixo como o comprimento, um enumeração como o tipo e uma sequência de bytes que contém os dados reais. Isso mantém todo o seu protocolo de rede transparente.

TCP/IP, assim como os pacotes UDP, incluem alguma referência ao seu tamanho. o Cabeçalho IP contém um campo de 16 bits que especifica o comprimento do cabeçalho IP e dados em bytes. o Cabeçalho TCP Contém um campo de 4 bits que especifica o tamanho do cabeçalho TCP em palavras de 32 bits. o Cabeçalho UDP contém um campo de 16 bits que especifica o comprimento do cabeçalho UDP e dados em bytes.

Aqui está a coisa.

Usando os soquetes comuns do Windows, estejam usando o espaço de nome System.net.sockets em C# ou o material de winsock nativo no Win32, você nunca vê os cabeçalhos IP/TCP/UDP. Esses cabeçalhos são despojados para que o que você obtém ao ler o soquete seja a carga útil real, ou seja, os dados que foram enviados.

O padrão típico de tudo que eu já vi e fiz usando soquetes é que você define um cabeçalho no nível do aplicativo que precede os dados que deseja enviar. No mínimo, esse cabeçalho deve incluir o tamanho dos dados a seguir. Isso permitirá que você leia cada "mensagem" na íntegra, sem ter que adivinhar o tamanho. Você pode se tornar tão chique quanto quiser, por exemplo, padrões de sincronização, CRCs, versão, tipo de mensagem etc., mas o tamanho da "mensagem" é tudo que você verdade precisar.

E pelo que vale a pena, sugiro usar um cabeçalho em vez de um delimitador de final de pacote. Não tenho certeza se há uma desvantagem significativa para o delimitador EOP, mas o cabeçalho é a abordagem usada pela maioria dos protocolos IP que eu já vi. Além disso, parece -me mais intuitivo processar uma mensagem desde o início, em vez de esperar que algum padrão apareça no meu fluxo para indicar que minha mensagem está completa.

EDIT: Acabei de tomar conhecimento do projeto Buffers do Google Protocol. Pelo que posso dizer, é um esquema de serialização/desperalização binária para o WCF (tenho certeza de que isso é uma simplificação excessiva). Se você está usando o WCF, não precisa se preocupar com o tamanho das mensagens que estão sendo enviadas porque o encanamento da WCF cuida disso nos bastidores, e é provavelmente por isso que você não encontrou nada relacionado ao comprimento da mensagem no protocolo Documentação de buffers. No entanto, no caso de soquetes, saber o tamanho ajudará tremendamente, conforme discutido acima. Meu palpite é que você serializa seus dados usando os buffers de protocolo e depois prenderá o cabeçalho do aplicativo que você criar antes de enviá -los. No lado de recebimento, você retirará o cabeçalho e despertaram o restante da mensagem.

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