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)