简体   繁体   English

时间测量UDP套接字C

[英]Time measure UDP socket C

I´m trying to obtain the performance in a Client (PC i7 3.4 GHz Kubuntu 15.04) - Server (RaspberryPi 700 Mhz Raspbian Jessie) architecture with sockets, measuring the spent time sending and receiving with at least microseconds precision. 我正在尝试在具有套接字的客户端(PC i7 3.4 GHz Kubuntu 15.04)-服务器(RaspberryPi 700 Mhz Raspbian Jessie)体系结构中获得性能,以至少微秒的精度测量发送和接收所花费的时间。

Concretely, I have a client (PC) that makes 100 times: 具体来说,我有一个客户端(PC),它的访问次数是100次:

  • Send UDP frame to server (Ta) 将UDP帧发送到服务器(Ta)
  • Receive UDP frame from server (Tb) 从服务器(Tb)接收UDP帧
  • Spent time is: T=Tb-Ta 花费的时间是:T = Tb-Ta

and a server (RaspberryPi) that makes 100 times: 和一台服务器(RaspberryPi),其性能是100倍:

  • Receive UDP frame from client(T1) 从客户端(T1)接收UDP帧
  • Send UDP frame from client(T2) 从客户端发送UDP帧(T2)
  • Spent time is: T'=T2-T1 花费的时间是:T'= T2-T1

I´m measuring time before send and after receive in client and subtracting it the time taken in server to receive and send, so the total time would be: Tt=TT' but sometimes I get negative measures... :S 我正在测量客户端发送之前和接收之后的时间,然后减去服务器接收和发送服务器所花费的时间,因此总时间为:Tt = TT',但有时我会得到负面的衡量标准...:S

I´m measuring with this macro, where in 'X' I placed my code (C:sendto()-recvfrom() or S:recvfrom()-sendto()): 我正在用此宏进行测量,在“ 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(..);
       }
   );
}

I have to measure time in any case, so another solution to obtain performance is not valid for me. 无论如何,我都必须测量时间,因此获取性能的另一种解决方案对我而言无效。

Can anyone suggest what can I do to solve this problem? 谁能建议我该怎么解决这个问题?

Than you so much. 比你好

(V2. EDITED WITH 'int64_t' and 'double' VALUES) (V2。使用“ int64_t”和“ double”值编辑)

Here is my full code. 这是我的完整代码。

It can be downloaded from: 可以从以下位置下载:
V1 - https://www.dropbox.com/sh/gb4mhn3amkyqhc1/AAC6FxKCfDxXQYgzRsjArvXQa?dl=0 V1- https: //www.dropbox.com/sh/gb4mhn3amkyqhc1/AAC6FxKCfDxXQYgzRsjArvXQa ? dl =0

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

server.c: server.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);
}

client.c client.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);
}

I get warnings in number formats, so I think that it is probably that printed values wouldn't be correct. 我收到数字格式的警告,因此我认为打印的值可能不正确。

These are warnings which I get: 这些是我得到的警告:

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(
             ^

You might be getting problems with converting these numbers to floating point. 将这些数字转换为浮点数时可能会遇到问题。 Try computing the difference into a suitably large integer datatype. 尝试将差异计算为适当的大整数数据类型。 At least to begin with, and then work back from there. 至少要从头开始,然后再从那里开始。

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 );

If you wanted a float out of that, beware that single-precision is pretty limited. 如果您想从中浮出水面,请注意单精度非常有限。 You may be able to clamp it to microseconds, but for longer intervals you might not get microsecond resolution. 您可能可以将其钳制到微秒,但是对于较长的时间间隔,您可能无法获得微秒的分辨率。

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

Better to use double: 最好使用double:

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

Of course, you could just use a timespec itself: 当然,您可以只使用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 );

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM