c - 时间测量 UDP 套接字 C

标签 c sockets time udp measure

我正在尝试在客户端 (PC i7 3.4 GHz Kubuntu 15.04) - 服务器 (RaspberryPi 700 Mhz Raspbian Jessie) 架构中获得性能,并以至少微秒的精度测量发送和接收所花费的时间。

具体来说,我有一个客户端(PC)可以赚 100 次:

  • 发送UDP帧到服务器(Ta)
  • 从服务器接收 UDP 帧 (Tb)
  • 花费的时间是:T=Tb-Ta

和一个能产生 100 次的服务器 (RaspberryPi):

  • 从客户端(T1)接收UDP帧
  • 从客户端发送UDP帧(T2)
  • 花费的时间是:T'=T2-T1

我测量客户端发送前和接收后的时间,减去服务器接收和发送所花费的时间,因此总时间为: Tt=T-T' 但有时我会得到消极的措施... :S

我用这个宏进行测量,我在“X”中放置了我的代码(C:sendto()-recvfrom() 或 S:recvfrom()-sendto()):

float timef=0.0;
#define TIME_MEASURE(X)                                        \
{                                                              \
  struct timespec ts1, ts2;                                    \
  clock_gettime( CLOCK_REALTIME, &ts1 );                       \
  X;                                                           \
  clock_gettime( CLOCK_REALTIME, &ts2 );                       \
  timef=(float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \
    + 1.0*ts2.tv_sec - 1.0*ts1.tv_sec ) );                     \
}

//Client pseudo-code example

main(){
   TIME_MEASURE(
       while(i<100)
       {
           sendto(...);
           recvfrom(..);
       }
   );
}

无论如何我都必须测量时间,所以另一种获得性能的解决方案对我无效。

谁能建议我该怎么做才能解决这个问题?

比你厉害

(V2。使用“int64_t”和“double”值进行编辑)

这是我的完整代码。

可从以下网址下载:
V1- https://www.dropbox.com/sh/gb4mhn3amkyqhc1/AAC6FxKCfDxXQYgzRsjArvXQa?dl=0

V2 - https://www.dropbox.com/sh/byipa75qruc71gj/AAD2ExMlnQSaUk_Pbc5xR2lZa?dl=0

服务器.c:

    /****************************************
 * Servidor UDP. Recibe como argumento
 * en linea de comandos el numero de puerto. El servidor
 * se ejecuta en bucle
 ***************************************/
#include <sys/types.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <pthread.h>
#define TAMANO 256

#include <sys/time.h>
#include <math.h>
#include <time.h>

void * ack();
void error_fatal(char *); /* Imprime un mensaje de error y sale del programa */




int sock, length, fromlen, n, i, j, port ;
struct sockaddr_in server;
struct sockaddr_in from;
char buffer[TAMANO];

float timeArr;
float timeVector[101];
double timed;

#define TIME_MEASURE(X)                                             \
{                                                                   \
    struct timespec ts1, ts2, diff;                                 \
    clock_gettime( CLOCK_REALTIME, &ts1 );                          \
    X;                                                              \
    clock_gettime( CLOCK_REALTIME, &ts2 );                          \
    timeArr= (float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \
     + 1.0*ts2.tv_sec - 1.0*ts1.tv_sec );                           \
     diff.tv_sec = ts2.tv_sec - ts1.tv_sec;                          \
     diff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec;                       \
     if( diff.tv_nsec < 0 ) {                                        \
         diff.tv_sec--;                                              \
         diff.tv_nsec += 1000000000LL;                               \
         }                                                               \
         printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
         const int64_t NANO = 1000000000LL;                              \
         int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO;       \
         nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec);                   \
         printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );\
         timed = (double)nsec * 1e-9;                                    \
         printf("nsec=%ld\n");                                           \
         }\

int main(int argc, char *argv[])
{

    timeArr=0.1;
    i=0;
    pthread_t recv;

    FILE *f;




    if (argc < 2) 
    {
        fprintf(stderr, "ERROR, no se ha indicado el puerto \n");
        exit(1);
    }

    /* obtain port number */
    if (sscanf(argv[1], "%d", &port) <= 0)
    {
        fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
    return -2;
    }

    /* (1) creacion del socket del servidor*/
    sock=socket(AF_INET, SOCK_DGRAM, 0);
    if (sock < 0) 
        error_fatal("Creando el socket");

    length = sizeof(server);
    memset(&server,0,length); /*limpio la direccion del socket del servidor*/

    /* (2) vinculo la direccion IP y puerto local al socket creado anteriormente */
    server.sin_family=AF_INET;
    server.sin_addr.s_addr=INADDR_ANY;
    server.sin_port=htons(port);

    if (bind(sock,(struct sockaddr *)&server,length)<0)
        error_fatal("binding");

    fromlen = sizeof(struct sockaddr_in);

    /* (3) bucle principal. Pongo a recibir y responder mensajes a traves del socket*/
    printf("Servidor listo y esperando tramas UDP en el puerto %d...\n", port);



    while (1) 
    {
        //el cliente manda una trama de prueba para no contar el tiempo de espera en el servidor
        //client sends init frame and it is not counted
        if(i==0)
        {
             //Recibo paquete de prueba para empezar a contar, desecho este tiempo
            n = recvfrom(sock,buffer,TAMANO,0,(struct sockaddr *)&from,&fromlen);
            pthread_create (&recv, NULL,ack, &fromlen);
            i++;            

        }
        else
        {

            TIME_MEASURE(

                n = recvfrom(sock,buffer,TAMANO,0,(struct sockaddr *)&from,&fromlen);

                if (n < 0) 
                    error_fatal("recvfrom");
                    /*datagrama recibido*/

                pthread_create (&recv, NULL,ack, &fromlen);
            );


            timeVector[i]=(float)timeArr;

            printf("timevector[%d] = %f\n", i, timeArr);

            if(i==100)
            {
                f=fopen("dataserver.txt", "w+");
                printf("Se han recibido 100 tramas UDP\n\n\n");

                for(j=0;j<=100;j++)
                {

                    fprintf(f,"%f\n",timeVector[j]);
                    //printf("valores: %f\n",timeVector[j]);
                }
                i=0;
                fclose(f);
                memset(timeVector,0,100);
            }
            else
            {
                i++;   
            }
        }

    }
    return 0;
}

void *ack(void *ptr){

    int *fl;

    fl= (int *)ptr;
    buffer[n]='\0'; /* para poder imprimirlo con prinft*/
    //printf("Recibido en el servidor: %s\n", buffer);

    /*enviar respuesta*/
    float t;

    t=(float)timeArr;

    //It is like an ACK, now I am not using this value
    n = sendto(sock,&t,sizeof(float),0,(struct sockaddr *)&from,fromlen);

    memset(buffer,0,TAMANO); 
    if (n < 0) 
         error_fatal("sendto"); 

    pthread_exit(NULL);
}

void error_fatal(char *msg)
{
 perror(msg);
 exit(1);
}

客户端.c

/*******************************************************************
 * Cliente de eco remoto sobre UDP:
 *
 * cliente dir_ip_maquina puerto
 ********************************************************************/
#include <sys/types.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#define TAMANO 256 /* tamano del buffer de recepcion */

#include <sys/time.h>
#include <math.h>
#include <time.h>

void error_fatal(char *); /* Imprime un mensaje de error y sale del programa */

float timeArr;
float timeVector[101];
int i;
double timed;



#define TIME_MEASURE(X)                                             \
{                                                                   \
    struct timespec ts1, ts2, diff;                                 \
    clock_gettime( CLOCK_REALTIME, &ts1 );                          \
    X;                                                              \
    clock_gettime( CLOCK_REALTIME, &ts2 );                          \
    timeArr= (float) ( 1.0*(1.0*ts2.tv_nsec - ts1.tv_nsec*1.0)*1e-9 \
     + 1.0*ts2.tv_sec - 1.0*ts1.tv_sec );                           \
     diff.tv_sec = ts2.tv_sec - ts1.tv_sec;                          \
     diff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec;                       \
     if( diff.tv_nsec < 0 ) {                                        \
         diff.tv_sec--;                                              \
         diff.tv_nsec += 1000000000LL;                               \
         }                                                               \
         printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
         const int64_t NANO = 1000000000LL;                              \
         int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO;       \
         nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec);                   \
         printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );\
         timed = (double)nsec * 1e-9;                                    \
         printf("nsec=%ld\n");                                           \
         }\



/*
 * 
 *    const int64_t NANO = 1000000000LL;                              \
    int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO;       \
    nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec);                   \
    printf( "Elapsed: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );\
                                                                    \

                                                                    */

int main(int argc, char *argv[])
{
    int sock; /* descriptor del socket del cliente */
    int length, n, j, port;
    struct sockaddr_in server, from; /* direcciones del socket del servidor y cliente */
    struct hostent *hp; /* estructura para el nombre del servidor (ver gethostbyname) */
    char buffer[TAMANO]; /* buffer de recepcion y envio del mensaje */
    char buffercpy[TAMANO];
    float bufferf[7];

    FILE *f = fopen("data.txt", "w+");
    struct timespec spec;
    clockid_t clk_id;

    clk_id=CLOCK_REALTIME;
    i=0;


    if (argc != 3) 
    { 
        fprintf(stderr,"Uso: ./client server port\n");
        exit(1);
    }

    /* obtain port number */
    if (sscanf(argv[2], "%d", &port) <= 0)
    {
    fprintf(stderr, "%s: error: wrong parameter: port\n", argv[0]);
    return -2;
    }
    printf("El cliente va a mandar por el puerto %d\n", port);

    /* (1) creacion del socket UDP del cliente */
    sock= socket(AF_INET, SOCK_DGRAM, 0); 
    if (sock < 0)   
        error_fatal("socket");    
    server.sin_family = AF_INET; /*dominio de Internet*/

    /* (2) averigua la direccion IP a partir del nombre del servidor*/
    hp = gethostbyname(argv[1]);
    if (hp==0) 
        error_fatal("Host desconocido");

    /* (3) copia la IP resuelta anteriormente en la direccion del socket del servidor */
    memcpy((char *)&server.sin_addr,(char *)hp->h_addr,hp->h_length);

   if ( clock_getres( clk_id, &spec) == -1 )
   {
      perror( "clock get resolution" );
      return EXIT_FAILURE;
    }

    //printf ("CLOCK_REALTIME: %ld s, %ld ns\n", spec.tv_sec,spec.tv_nsec); 

    /* (4) copia el puerto destino en la direccion del socket del servidor */
    server.sin_port = htons(port);
    length=sizeof(struct sockaddr_in);

    printf("Por favor, introduce el mensaje: ");
        memset(buffer,0,TAMANO); /*limpio el buffer*/
        fgets(buffer,TAMANO-1,stdin);
        strcpy(buffercpy, buffer);//Copio el mensaje a un nuevo buffer para que se repita en el while


    while(i<=100)
    {       
        //client sends init frame and it is not counted
        if(i==0)
        {

            /* (5) envia al socket del servidor el mensaje almacenado en el buffer*/
            n=sendto(sock,buffer,strlen(buffer),0,(struct sockaddr *) &server,length);
            if (n < 0) 
                error_fatal("Sendto");

            /* (6) lee del socket el mensaje de respuesta del servidor*/
            n = recvfrom(sock,bufferf,sizeof(float),0,(struct sockaddr *) &from, &length);

            if (n < 0) 
                error_fatal("recvfrom");
            i++;

        }
        else
        {




            TIME_MEASURE(
                memset(buffer, '\0', sizeof(buffer));
                strcpy(buffer, buffercpy);

                /* (5) envia al socket del servidor el mensaje almacenado en el buffer*/
                n=sendto(sock,buffer,strlen(buffer),0,(struct sockaddr *) &server,length);
                if (n < 0) 
                    error_fatal("Sendto");

                /* (6) lee del socket el mensaje de respuesta del servidor*/
                n = recvfrom(sock,bufferf,sizeof(float),0,(struct sockaddr *) &from, &length);

                if (n < 0) 
                    error_fatal("recvfrom");

            );

            timeVector[i]=(float)timeArr;
            printf("Tiempo de procesamiento cliente - timeVector [%d]: %f\n", i,timeArr);

            //timeVector[i]+=(float)(0.0 - *bufferf);
            //printf("timeVector negativo[%d]= %f\n", i, timeVector[i]);
            buffer[n]='\0'; /* para poder imprimirlo con printf*/
            bufferf[n]='\0'; /* para poder imprimirlo con printf*/
            //printf("Recibido en el cliente: %f ACK(%d)%c\n",*bufferf,i,'\0');


            printf("timeVector TOTAL= %f\n\n", timeVector[i]);
            //printf("buffer=%s%c\n",buffer,'\0');

            if(i==100){
                for(j=1;j<=100;j++){
                    fprintf(f,"%f\n",timeVector[j]);
                        //printf("valores: %f\n",timeVector[j]);
                }
                printf("Se han enviado 100 tramas UDP \n\n\n");

            }
            i++;
        }
    }

    fclose(f);
    /*cerramos el socket*/
    if(close(sock) < 0) 
        error_fatal("close");
}

void error_fatal(char *msg)
{
    perror(msg);
    exit(1);
}

我收到了数字格式的警告,所以我认为打印的值可能不正确。

这些是我收到的警告:

server.c: In function ‘main’:
server.c:50:18: warning: format ‘%u’ expects argument of type ‘unsigned int’, but argument 2 has type ‘__time_t {aka long int}’ [-Wformat=]
          printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
                  ^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
             TIME_MEASURE(
             ^
server.c:50:18: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘__syscall_slong_t {aka long int}’ [-Wformat=]
          printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );\
                  ^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
             TIME_MEASURE(
             ^
server.c:54:18: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 2 has type ‘long int’ [-Wformat=]
          printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO )
                  ^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
             TIME_MEASURE(
             ^
server.c:54:18: warning: format ‘%lld’ expects argument of type ‘long long int’, but argument 3 has type ‘long int’ [-Wformat=]
          printf( "Elapsed nsec: %lld.%09lld secs\n", nsec / NANO, nsec % NANO )
                  ^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
             TIME_MEASURE(
             ^
server.c:56:17: warning: format ‘%ld’ expects a matching ‘long int’ argument [-Wformat=]
          printf("nsec=%ld\n");                                           \
                 ^
server.c:122:13: note: in expansion of macro ‘TIME_MEASURE’
             TIME_MEASURE(
             ^

最佳答案

您可能会在将这些数字转换为 float 时遇到问题。尝试将差异计算为适当大的整数 数据类型。至少从一开始,然后从那里开始。

const int64_t NANO = 1000000000LL;
int64_t nsec = (int64_t)(ts2.tv_sec - ts1.tv_sec) * NANO;
nsec += (int64_t)(ts2.tv_nsec - ts1.tv_nsec);
printf( "Elapsed: %lld.%09lld secs\n", nsec / NANO, nsec % NANO );

如果您想要一个 float ,请注意单精度非常有限。您可能能够将其限制在微秒级,但对于更长的间隔,您可能无法获得微秒级分辨率。

timef = (float)(nsec / 1000LL) * 1e-6f;

最好使用double:

double timef;
timef = (double)nsec * 1e-9;

当然,您可以只使用 timespec 本身:

struct timespec diff;
diff.tv_sec = ts2.tv_sec - ts1.tv_sec;
diff.tv_nsec = ts2.tv_nsec - ts1.tv_nsec;
if( diff.tv_nsec < 0 ) {
    diff.tv_sec--;    
    diff.tv_nsec += 1000000000LL;
}
printf( "Elapsed: %u.%09lld secs\n", diff.tv_sec, diff.tv_nsec );

关于c - 时间测量 UDP 套接字 C,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36178105/

相关文章:

c - 为什么此代码的行为在 C 中未定义?

sockets - 将部分数据包写入 SSL BIO

c++ - 在 C++ 中获取/设置日期和时间

ios - 如何将我的 UILabel 与系统时间同步?

datetime - 如果 UTC 时间戳可用,时区信息是否多余?

C: 将 "static const char * const"分配给 "static const char *"

c - 如何在gcc中使用struct?

合并字节的c函数

c++ - socketpair() & 在 worker socket 的 close() 之后创建新的子进程

python - 为什么在 python 中使用套接字嗅探 wifi 帧时我得到以太网帧(不是 802.11)