Por que o ping é muito mais rápido do que os soquetes do UDP?

3

Estou tentando avaliar com que velocidade os soquetes UDP estão em minha rede local.

Por meio do ping do meu endereço IP local, obtenho um tempo de ida e volta de ~ 80 microssegundos.

Eu escrevi um servidor UDP e um cliente mínimos para avaliar a latência da seguinte forma. O cliente e o servidor estão executando no mesmo host, usando a mesma interface de rede. O cliente envia um timeval para o servidor por meio de soquetes de datagrama e, após o recebimento, o servidor leva imediatamente a diferença entre o timeval atual e o timeval recebido. Fazendo isso, eu obtive ~ 110 microssegundos para uma viagem unidirecional, para um total 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, '
#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, '
cc udpserver.c -o udpserver
cc udpclient.c -o udpclient
./udpserver 4321
./udpclient 127.0.0.1 4321
', 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; }
', 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 <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, '
#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, '%pre%', 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;
}
', 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; }
    
por ajkshdkjlasdl123123 12.06.2016 / 05:03

1 resposta

3

Palpite:

ping é uma ferramenta que usa o protocolo icmp . icmp fica na camada 3, a camada de rede, do modelo OSI.

udpclient.c é uma ferramenta que usa o protocolo udp . 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 pacote icmp contém um endereço IP de origem e um endereço IP de destino. Um datagrama udp contém tudo isso mais e. g. as informações da porta UDP. Esta informação de porta precisa ser interpretada por um nível mais alto na pilha de rede.

Portanto, os pacotes UDP precisam subir um nível a mais na pilha da rede. Pode-se imaginar tomando as escadas para o 4º andar em vez do 3º andar. Levará mais tempo, por mais que 30µs.

Eu acredito que esses 30µs consistem em

  • tamanho dos dados icmp vs udp
  • NIC / driver / tempo de CPU para encapsular e decapsular
  • Tempo de CPU que udpclient.c usa
por 12.06.2016 / 08:26

Tags