Os pacotes TCP e UDP podem ser divididos em partes?

41

Pacotes TCP podem chegar ao receptor em pedaços?

Por exemplo, se eu enviar 20 bytes usando o protocolo TCP, posso ter 100% de certeza de que receberei exatamente 20 bytes de uma só vez, não 10 bytes e outros 10 bytes?

E a mesma pergunta para o protocolo UDP.
Eu sei que o UDP não é confiável e os pacotes não podem chegar nem chegar em ordem diferente, mas e quanto a um único pacote? Se chegar, posso ter certeza de que é um pacote completo, não um pedaço?

iamnp
fonte
7
Um ponto de esclarecimento: é chamado de segmento TCP e um datagrama UDP. Eles não são pacotes. TCP = Segmento, UDP = Datagrama, IP = Pacote, Ethernet = Quadro, Em todas as outras camadas (AFAIK), elas são chamadas de PDUs (Protocol Data Units).
precisa saber é o seguinte

Respostas:

33

pacotes TCP podem chegar ao receptor em pedaços?

Sim. O IP suporta fragmentação, embora o TCP geralmente tente determinar o caminho MTU e mantenha seus pacotes menores que por motivos de desempenho. A fragmentação aumenta a taxa de perda de datagramas catastroficamente. Se um caminho tem uma taxa de perda de 10% de pacotes, fragmentar um datagrama em dois pacotes torna a taxa de perda de datagrama quase 20%. (Se um dos pacotes for perdido, o datagrama será perdido.)

Você não precisa se preocupar com isso, e a camada TCP também não. A camada IP remonta pacotes em datagramas inteiros.

Por exemplo: se eu enviar 20 bytes usando o protocolo TCP, posso ter 100% de certeza de que receberei exatamente 20 bytes de uma só vez, não 10 bytes e outros 10 bytes?

Não, mas isso não tem nada a ver com pacotes. O TCP é, fundamentalmente, um protocolo de fluxo de bytes que não preserva os limites das mensagens do aplicativo.

E a mesma pergunta para o protocolo UDP. Eu sei que o UDP não é confiável e os pacotes não podem chegar nem chegar em ordem diferente,

O mesmo vale para o TCP. Pacotes são pacotes. A diferença é que o TCP tem novas tentativas e reordenações incorporadas ao protocolo, enquanto o UDP não.

mas e quanto a 1 pacote? Se chegar, posso ter certeza de que é um pacote completo, não um pedaço?

Não, mas esse não é o seu problema. O protocolo UDP trata da remontagem de datagramas. Isso faz parte do seu trabalho. (Na verdade, o protocolo IP faz isso para o protocolo UDP, então o UDP faz isso apenas colocando-o em camadas sobre o IP.) Se um datagrama é dividido em dois pacotes, o protocolo IP o remontará para o protocolo UDP, para que você verá os dados completos.

David Schwartz
fonte
10
Pode valer a pena esclarecer o último bit para leitores iniciantes: você verá os dados completos para o datagrama em questão . Se algum dos pacotes divididos for perdido, o datagrama será perdido e a camada UDP nunca o saberá. Desde que todos os pacotes no datagrama sejam recebidos, eles serão montados na camada IP e depois passados ​​para a camada UDP. Isso não impede a possibilidade de "pedaços" ausentes no fluxo de dados. Não para ser um pedante, mas quando eu estava aprendendo essas coisas, não percebi a diferença entre fragmentos de IP e perda de UDP até a segunda ou terceira passagem pelo livro.
precisa saber é o seguinte
20

Você não pode ter certeza de que eles realmente chegam fisicamente de uma só vez. As camadas de vínculo de dados abaixo de TCP / UDP podem dividir seu pacote, se desejar. Especialmente se você enviar dados pela Internet ou por qualquer rede fora do seu controle, é difícil prever isso.

Mas não importa se os dados chegam em um pacote ou em vários pacotes no receptor. O sistema operacional deve abstrair a concatenação desses pacotes; portanto, para o seu aplicativo, ainda parece que tudo chegou ao mesmo tempo. Portanto, a menos que você seja um hacker de kernel, na maioria dos casos você não precisa se preocupar se esses dados são transferidos em um ou muitos pacotes.

Para o UDP, o sistema operacional também fará alguma abstração, portanto, o aplicativo que recebe os dados não precisa saber em quantos pacotes os dados foram transmitidos. Mas a diferença para o TCP é que não há garantia de que os dados realmente cheguem. Também é possível que os dados sejam divididos em vários pacotes, e alguns deles chegam e outros não. De qualquer forma, para o aplicativo de recebimento, parece um fluxo de dados, independentemente de estar completo ou não.

repetição
fonte
O driver da placa de rede não se encarrega de remontar pacotes e não o kernel?
precisa saber é o seguinte
2
@ Hallucynogenyc: A menos que as coisas mudem, o protocolo da Internet é projetado para permitir que pacotes com mais de 576 bytes sejam divididos a qualquer momento da jornada, mas não espera que nada além do destinatário final os recombine. Eu acho que a idéia é que o uso de pacotes maiores foi na maioria dos casos um esforço para reduzir a sobrecarga; uma vez que um pacote tenha sido dividido em algum momento de sua jornada, a sobrecarga já foi incorrida e recombinada antes que o destinatário final não esteja apto a ajudar em nada, e poderá ser prejudicial se precisar ser re-dividido.
Supercat
Acredito que, embora qualquer pacote com mais de 576 bytes possa ser dividido, pacotes abaixo desse tamanho podem não; sistemas embarcados que não conseguem lidar com pacotes divididos devem evitar pedir algo maior que isso.
Supercat
1
@ mauro.stettler: Escrevi uma pilha TCP em "bare metal" (escrevi o código para falar diretamente com vários chips de interface de rede). Para hardware que fala com um link com um limite de 576 bytes para dividir pacotes mais longos, é simples. A remontagem de pacotes é muito mais complicada, principalmente porque é possível receber partes de muitos pacotes diferentes antes que qualquer um seja recebido na íntegra.
supercat 27/08/13
Há alguma esperança de que ele não seja dividido em pequenas cargas úteis (cerca de 10 ou 20 bytes devem estar ok), porque existe um "tamanho máximo garantido" necessário para cada salto para paquetes IP no ipv4: pelo menos 68 bytes (incluindo Cabeçalhos IP e sem contar os cabeçalhos de nível inferior). consulte a 1ª tabela em en.wikipedia.org/wiki/Maximum_transmission_unit . Diferente dos 576 bytes de tamanho mínimo exigido dos HOSTS (ou seja, a origem ou o fim da transmissão, nem todos os saltos intermediários). E cuidado: a carga útil é ainda mais baixa (pois os cabeçalhos de cada camada ocupam algum espaço).
Olivier Dulac
14

Exemplos. Blocos de caracteres contíguos correspondem a chamadas send ():

TCP:

Send: AA BBBB CCC DDDDDD E         Recv: A ABB B BCC CDDD DDDE

Todos os dados enviados são recebidos em ordem, mas não necessariamente nos mesmos blocos.

UDP:

Send: AA BBBB CCC DDDDDD E         Recv: CCC AA E

Os dados não estão necessariamente na mesma ordem e nem sempre são recebidos, mas as mensagens são preservadas na sua totalidade.

Jim Cote
fonte
5

Por exemplo: se eu enviar 20 bytes usando o protocolo TCP, posso ter 100% de certeza de que receberei exatamente 20 bytes de uma só vez, não 10 bytes e outros 10 bytes?

Não, o TCP é um protocolo de fluxo, mantém os dados em ordem, mas não os agrupa por mensagem. Por outro lado, o UDP é orientado a mensagens, mas não confiável. O SCTP tem o melhor dos dois mundos, mas não é nativamente utilizável porque os NATs quebram a Internet.

Changaco
fonte
1

Há alguma garantia de que, se você enviar 20 bytes no início de um fluxo TCP, ele não chegará como duas partes de 10 bytes. Isso ocorre porque a pilha TCP não envia segmentos tão pequenos: existe um tamanho mínimo de MTU. No entanto, se o envio estiver em qualquer lugar no meio de um fluxo, todas as apostas serão desativadas. Pode ser que sua pilha de protocolos use 10 bytes dos dados para preencher um segmento e enviá-lo e, em seguida, os próximos dez bytes vão para outro segmento.

Sua pilha de protocolos divide os dados em pedaços e os coloca em uma fila. Os tamanhos dos pedaços são baseados no caminho MTU. Se você executar uma operação de envio e ainda houver dados na fila pendentes, a pilha de protocolos normalmente examinará o segmento que está no final da fila e verificará se há espaço nesse segmento para adicionar mais dados. A sala pode ter o tamanho de um byte, portanto, mesmo um envio de dois bytes pode ser dividido em dois.

Por outro lado, a segmentação de dados significa que pode haver leituras parciais. Uma operação de recebimento pode potencialmente ativar e obter dados quando chega apenas um segmento. Na API de soquetes amplamente implementada, uma chamada de recebimento pode solicitar 20 bytes, mas pode retornar com 10. Obviamente, uma camada de buffer pode ser construída nela, bloqueando até que 20 bytes sejam recebidos ou a conexão quebre. No mundo POSIX, essa API pode ser o fluxo de E / S padrão: você pode usar fdopenum descritor de soquete para obter um FILE *fluxo e usá fread-lo para preencher um buffer, de modo que a solicitação completa seja satisfeita com o número de readchamadas necessárias. .

Os datagramas UDP enquadram os dados. Cada chamada de envio gera um datagrama (mas veja abaixo sobre rolhas). O outro lado recebe um datagrama completo (e, na API do soquete, ele deve especificar um buffer grande o suficiente para retê-lo, caso contrário, o datagrama será truncado). Os datagramas grandes são fragmentados pela fragmentação de IP e são remontados de forma transparente aos aplicativos. Se algum fragmento estiver ausente, o datagrama inteiro será perdido; não há como ler dados parciais nessa situação.

Existem extensões para a interface, permitindo que várias operações especifiquem um único datagrama. No Linux, um soquete pode ser "arrolhado" (impedido de enviar). Enquanto estiver arrolhado, os dados gravados são reunidos em uma única unidade. Então, quando o soquete é "desarrolhado", um único datagrama pode ser enviado.

Kaz
fonte
isso é falso: se alguém enviar um paquet com uma carga útil de 10 ou 20 bytes, isso gerará 1 paquet e (como eu disse acima), se estiver usando o ipv4, deverá, mesmo ao adicionar todos os cabeçalhos das outras camadas de protocolo, caber dentro de 68 bytes, garantindo assim que ele passe por todos os saltos em 1 pacote. A pilha Tcp não espera (como está indicado no seu primeiro parágrafo) "esperar até que o mtu seja preenchido (por exemplo, adicione vários pacotes para criar um tamanho adequado)" para enviar um pacote! ... Esse comportamento quebraria muitas coisas ( mesmo que esses "fragmentos" foram enviados de e para o mesmo par de hosts)
Olivier Dulac
@ OlivierDulac: Isso está incorreto. O TCP geralmente gera pacotes conforme necessário, tentando otimizar o uso da rede, para que 20 bytes possam terminar em dois pacotes diferentes, conforme explicado por Kaz. Isso pode ser controlado usando a opção de soquete TCP_NODELAY , que desativa o algoritmo Nagles que envia bytes para pacotes, se seu aplicativo precisar de uma rede TCP mais rápida. Além disso, 68 bytes não são de forma alguma o padrão de fato para o tamanho do pacote: 1500 bytes é um valor padrão mais comum (isso realmente varia entre as redes).
Jjmontes