O Linux está limitando as transferências UDP do meu aplicativo e como posso vê-lo?

2

Atualmente, estou desenvolvendo dois aplicativos para trabalhar em um "protocolo" de streaming de vídeo personalizado. Basicamente:

  • O servidor captura quadros de vídeo de uma webcam, divide-os em partes e envia essas peças para os clientes por meio do UDP.
  • Os clientes recebem todas as partes dos quadros e lidam com todos os "reordenamentos": colocando as partes na ordem correta, armazenando novos quadros "sobre" os antigos, e assim por diante ... Aqui é onde um "protocolo" era implementado: os clientes precisam entender os dados de vídeo que recebem, para que possam reordenar as coisas corretamente e exibir um quadro adequado .

O mecanismo em si funciona perfeitamente bem (depois de muita luta eu admito). No entanto, agora que meus aplicativos estão em execução, encontro meu cliente lutando para receber algumas partes de quadros. O cliente recuperará com sucesso as partes dos primeiros, digamos, quadros n e, em seguida, apenas ... espera em recvfrom . Eu não vou incomodar você com todos os detalhes dos aplicativos, mas aqui estão algumas estatísticas:

  • O servidor captura um quadro (38,016 bytes) a cada 40.000 microssegundos (25 fps).
  • Cada quadro é dividido em 24 partes (38,016 / 24 = 1584 bytes por peça).

Vamos supor que tenhamos apenas 1 cliente. No lado da rede, isso significa que:

  • A cada 40.000 microssegundos, o servidor envia 24 buffers para o cliente ( sendto ). Cada buffer tem 1584 bytes de comprimento. Por outro lado, o cliente chama recvfrom 24 vezes.
  • Em um segundo, o servidor pode capturar 25 quadros. Isso significa que, em 1s, ele enviará 25 * 24 quadros ao cliente. Isso representa 25 * 24 * 1584 = 950.400 bytes por segundo).

Também presumiremos que o cliente esteja sempre escutando quando o servidor estiver enviando. Agora, com essas taxas, o cliente poderá manter por 1 ou 2 segundos. Enquanto o aplicativo não congela, o cliente acabará por ficar pendurado em recvfrom , como se o servidor tivesse parado a transmissão.

Eu adicionei um pouco de verbosidade ao meu servidor para garantir que ele continuasse transmitindo, e isso acontece. Após alguns segundos, parece que as chamadas sendto do servidor não atingem mais as chamadas recvfrom do cliente. Eu verifiquei todo o meu código relacionado à rede e, como é bem simples, não há muito a se errar: o servidor constrói um buffer, chama sendto e começa a preparar o próximo buffer ... O cliente simplesmente aguarda para buffers.

Como não consigo encontrar uma explicação na programação, estou começando a acreditar que algo está ... preso na rede. Parece que algo, em algum lugar, está impedindo que meus pacotes UDP cheguem ao cliente depois de algum tempo. Agora, como o UDP é totalmente livre de controle, não consigo encontrar uma maneira de verificar o transporte de meus buffers do meu programa.

No entanto, haveria uma maneira de eu ver se o sistema faz transmitir meus pacotes, ou se eventualmente atinge um dos seus limites, e começa a descartá-los? Em caso afirmativo, o que é este limitando mecanismo, e há uma maneira que eu poderia configurar o meu sistema para permitir que meus aplicativos funcionem na taxa que eu programou-los para trabalhar?

Como meus aplicativos se comunicam pela interface de loopback (servidor em 127.0.0.1:n), achei que seria uma boa ideia adicionar informações sobre essa interface. Estou executando um sistema GNU / Linux (kernel 3.13.0).

$ ifconfig lo
lo    Link encap:Local Loopback  
      inet addr:127.0.0.1  Mask:255.0.0.0
      inet6 addr: ::1/128 Scope:Host
      UP LOOPBACK RUNNING  MTU:65536  Metric:1
      RX packets:98821 errors:0 dropped:0 overruns:0 frame:0
      TX packets:98821 errors:0 dropped:0 overruns:0 carrier:0
      collisions:0 txqueuelen:0 
      RX bytes:202639359 (202.6 MB)  TX bytes:202639359 (202.6 MB)
    
por John WH Smith 17.12.2014 / 22:30

1 resposta

3

Você pode usar tcpdump para monitorar pacotes nos dois lados. A ferramenta pode ser usada para capturar cabeçalhos ou pacotes completos. A página man inclui exemplos de como filtrar pacotes, para que você capture apenas o tráfego de seu interesse.

O tamanho do seu pacote parece um pouco estranho. Se você não estiver usando quadros jumbo, seus pacotes provavelmente serão fragmentados para transmissão na rede. Esta pode ser a causa do seu problema.

Cuspir os quadros em partes de 1472 bytes ou menos seria mais apropriado para uma conexão ethernet. A conexão à Internet pode ter um MTU ainda menor e partes de 1464 bytes ou menos podem ser mais apropriadas.

Você pode querer fazer uma descoberta de MTU na conexão para evitar a fragmentação. Isso permitiria evitar ou limitar a fragmentação de pacotes.

    
por 18.12.2014 / 00:21