Os pacotes TCP e UDP podem ser divididos em partes?

37

Os pacotes TCP podem chegar ao receptor por partes?

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 depois 10 bytes ou mais?

E a mesma pergunta para o protocolo UDP.
Eu sei que o UDP não é confiável e os pacotes não podem chegar ou 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?

    
por iamnp 27.08.2013 / 12:02

5 respostas

29

can TCP packets arrive to receiver by pieces?

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

Você não precisa se preocupar com isso, nem com a camada TCP. A camada IP reagrupa os pacotes em datagramas inteiros.

E.g.: if I send 20 bytes using TCP protocol, can I be 100% sure that I will receive exactly 20 bytes at once, not 10 bytes then another 10 bytes or so?

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.

And the same question for UDP protocol. I know that UDP is unreliable and packets can not arrive at all or arrive in different order,

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

but what about 1 packet? If it arrives, can I be sure that it is a complete packet, not a piece?

Não, mas isso não é problema seu. O protocolo UDP lida com a 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 simplesmente sendo colocado em camadas em cima do IP.) Se um datagrama é dividido em dois pacotes, o protocolo IP irá remontá-lo para o protocolo UDP. verá os dados completos.

    
por 27.08.2013 / 12:27
19

Você não pode ter certeza de que eles realmente chegam fisicamente de uma só vez. As camadas de enlace de dados abaixo de TCP / UDP podem dividir seu pacote se quiserem. 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, então, para a sua aplicação, ainda parece que tudo chegou ao mesmo tempo. Então, 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 SO 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. Para o aplicativo de recebimento, parece apenas um fluxo de dados, independentemente de estar completo ou não.

    
por 27.08.2013 / 12:04
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 não são necessariamente recebidos, mas as mensagens são preservadas na sua totalidade.

    
por 27.08.2013 / 18:22
5

E.g.: if I send 20 bytes using TCP protocol, can I be 100% sure that I will receive exactly 20 bytes at once, not 10 bytes then another 10 bytes or so?

Não, o TCP é um protocolo de fluxo, ele mantém os dados em ordem, mas não os agrupa por mensagem. Por outro lado, o UDP é orientado para 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.

    
por 27.08.2013 / 12:19
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 enviará segmentos tão pequenos: há um tamanho mínimo de MTU. No entanto, se o envio estiver em qualquer lugar no meio de um fluxo, todas as apostas estão desativadas. Pode ser que sua pilha de protocolos tome 10 bytes dos dados para preencher um segmento e enviá-lo para fora e, em seguida, os próximos dez bytes vão para outro segmento.

Sua pilha de protocolos divide os dados em blocos e os coloca em uma fila. Os tamanhos dos blocos baseiam-se no caminho MTU. Se você executar uma operação de envio e ainda houver dados enfileirados pendentes, a pilha de protocolos geralmente observará o segmento que está na parte final da fila e verá se há espaço nesse segmento para adicionar mais dados. A sala poderia ser tão pequena quanto um byte, então até mesmo um envio de dois bytes poderia ser dividido em dois.

No outro extremo, a segmentação de dados significa que pode haver leituras parciais. Uma operação de recebimento pode potencialmente despertar e obter dados quando chega apenas um segmento. Na API de sockets amplamente implementada, uma chamada de recebimento pode solicitar 20 bytes, mas pode retornar com 10. Naturalmente, uma camada de buffer pode ser construída nela, bloqueando até que 20 bytes sejam recebidos ou que a conexão seja interrompida. No mundo POSIX, essa API pode ser os fluxos de E / S padrão: você pode fdopen um descritor de soquete para obter um FILE * stream, e você pode usar fread para preencher um buffer de forma que o pedido completo está satisfeito com o número de read de chamadas necessárias.

Os datagramas UDP enquadram os dados. Cada chamada de envio gera um datagrama (mas veja abaixo sobre corking). O outro lado recebe um datagrama completo (e, na API de soquete, ele deve especificar um buffer grande o suficiente para mantê-lo, senão o datagrama será truncado). Datagramas grandes são fragmentados por fragmentação de IP e são remontados de forma transparente aos aplicativos. Se algum fragmento estiver faltando, todo o datagrama 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 socket pode ser "corked" (impedido de enviar). Enquanto é arrolhada, os dados escritos são reunidos em uma única unidade. Então, quando o soquete é "uncorked", um único datagrama pode ser enviado.

    
por 27.08.2013 / 18:56