Estou tentando avaliar a velocidade dos soquetes UDP na minha rede local.
Ao executar ping em meu endereço IP local, obtenho um tempo de ida e volta de aproximadamente 80 microssegundos.
Escrevi um servidor e cliente UDP mínimo para avaliar a latência da seguinte maneira. O cliente e o servidor estão sendo executados no mesmo host, usando a mesma interface de rede. O cliente envia um intervalo de tempo para o servidor por meio de soquetes de datagrama e, após o recebimento, o servidor imediatamente calcula a diferença entre o intervalo de tempo atual e o intervalo de tempo recebido. Fazendo isso, obtenho aproximadamente 110 microssegundos para uma viagem só de ida, para um total de cerca de aproximadamente 220 microssegundos RTT.
Por que o ping é muito mais rápido que o meu programa?
cc udpserver.c -o udpserver
cc udpclient.c -o udpclient
./udpserver 4321
./udpclient 127.0.0.1 4321
udpserver.c
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
void error(char *msg)
{
perror(msg);
exit(1);
}
int main(int argc, char *argv[])
{
int sockfd, newsockfd, portno;
struct timeval tval_recv, tval_now;
struct sockaddr_in serv_addr;
int n;
/* Check arguments */
if (argc < 2) {
fprintf(stderr,"ERROR, no port provided\n");
exit(1);
}
/* Set up socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("ERROR opening socket");
/* Setup socket address for server */
memset((char *) &serv_addr, '\0', sizeof(serv_addr));
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;
serv_addr.sin_port = htons(atoi(argv[1]));
/* Bind socket to socket address */
if(bind(sockfd, (struct sockaddr *) &serv_addr,
sizeof(serv_addr)) < 0)
error("ERROR on binding");
while(1) {
n = recvfrom(sockfd, &tval_recv, sizeof(tval_recv), 0, NULL, NULL);
if(n < 0)
error("ERROR in recvfrom");
gettimeofday(&tval_now, NULL);
printf("%ld.%06ld\n", tval_now.tv_sec - tval_recv.tv_sec,
(long int)(tval_now.tv_usec - tval_recv.tv_usec));
}
return 0;
}
udpclient.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
void error(char *msg) {
perror(msg);
exit(0);
}
int main(int argc, char **argv) {
in_addr_t s_addr;
int sockfd, portno, n;
struct sockaddr_in serveraddr;
struct timeval tval;
// struct timespec ts_current;
/* Check arguments */
if (argc != 3) {
fprintf(stderr,"Usage: %s <hostname> <port>\n", argv[0]);
exit(0);
}
/* Create the socket */
sockfd = socket(AF_INET, SOCK_DGRAM, 0);
if (sockfd < 0)
error("Error opening socket");
/* Set the socket address */
s_addr = inet_addr(argv[1]);
portno = atoi(argv[2]);
memset((char *) &serveraddr, '\0', sizeof(serveraddr));
memcpy(&serveraddr.sin_addr.s_addr, &s_addr, sizeof(s_addr));
serveraddr.sin_family = AF_INET;
serveraddr.sin_port = htons(atoi(argv[2]));
/* Send packets */
while(1) {
gettimeofday(&tval, NULL);
// clock_gettime(CLOCK_MONOTONIC, &ts_current);
n = sendto(sockfd, &tval, sizeof(tval), 0, (struct sockaddr *)&serveraddr,
sizeof(serveraddr));
if(n < 0)
error("ERROR in sendto");
sleep(1);
}
return 0;
}
Responder1
Palpite ousado:
ping
é uma ferramenta que usa o icmp
protocolo. icmp
fica na camada 3, a camada de rede, do modelo OSI.
udpclient.c
é uma ferramenta que usa o udp
protocolo. udp
fica na camada 4, a camada de transporte, do modelo OSI.
Com cada camada, dados adicionais serão adicionados aos dados brutos. Como exemplo básico: um icmp
pacote contém um endereço IP de origem e um endereço IP de destino. Um udp
datagrama contém tudo isso, além, por exemplo, das informações da porta UDP. Essas informações de porta precisam ser interpretadas por um nível superior na pilha da rede.
Portanto, os pacotes UDP precisam subir mais um nível na pilha da rede. Poderíamos imaginar subir as escadas para o 4º andar em vez do 3º andar. Levará mais tempo, porém muito mais que 30 µs.
Acredito que esses 30µs consistem em
- tamanho dos dados
icmp
versusudp
- Tempo de NIC/driver/CPU para encapsular e desencapsular
- Tempo de CPU que
udpclient.c
usa