2016-03-23 9 views
2

Ich versuche, die Leistung in einem Client (PC i7 3.4 GHz Kubuntu 15.04) - Server (RaspberryPi 700 Mhz Raspbian Jessie) Architektur mit Sockets, messen die verbrachte Zeit Senden und Empfangen mit mindestens Mikrosekunden Genauigkeit.Zeit messen UDP Socket C

Konkret habe ich einen Client (PC), die 100-mal macht:

  • senden UDP Frame-Server (Ta)
  • Erhalten UDP Rahmen von Server (Tb)
  • Benötigte Zeit ist: T = Tb-Ta

und ein Server (Raspberry Pi), die 100-mal macht:

    Erhalten 10
  • UDP-Rahmen vom Client (T1)
  • Senden UDP Frame von dem Client (T2)
  • Spent Zeit ist: T '= T2-T1

ich bin Meßzeit vor senden und empfangen, nachdem in Client und es ist die Zeit in Server, zu empfangen und senden genommen Subtrahieren so würde die Gesamtzeit sein: Tt = TT‘ aber manchmal bekomme ich negativ Maßnahmen ...: S

ich bin mit diesem Makro Mess , wo in 'X' habe ich meinen Code (C: sendto() - recvfrom() oder 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(..); 
     } 
    ); 
} 

Ich muss die Zeit auf jeden Fall messen, so eine andere Lösung, um Leistung zu erhalten, ist nicht gültig für mich.

Kann jemand vorschlagen, was kann ich tun, um dieses Problem zu lösen?

Als Sie so sehr.

(V2. EDITED MIT 'int64_t' und 'double' VALUES)

Hier ist meine vollständige Code.

Es kann heruntergeladen werden unter:
V1 - https://www.dropbox.com/sh/gb4mhn3amkyqhc1/AAC6FxKCfDxXQYgzRsjArvXQa?dl=0

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

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

/******************************************************************* 
* 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); 
} 

Ich bekomme Warnungen in Zahlenformaten, daher denke ich, dass die gedruckten Werte wahrscheinlich nicht korrekt sind.

Dies sind Warnungen, die ich erhalten:

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

Ich schlage vor, mit 'double' und nicht' float', da Der Zahlenbereich ist zwischen Sekunden und Nanosekunden so groß. 'timed = 1e-9 * (ts2.tv_nsec - ts1.tv_nsec) + ts2.tv_sec - ts1.tv_sec;' –

Antwort

0

Sie könnten immer Probleme werden mit diesen Zahlen zu Gleitkomma-Umwandlung.Versuchen Sie, die Differenz in einen geeigneten großen Integer Datentyp zu berechnen. Zumindest zu Beginn und dann von dort aus arbeiten.

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

Wenn Sie einen Float daraus machen wollten, achten Sie darauf, dass Single-Precision ziemlich begrenzt ist. Sie können es möglicherweise in Mikrosekunden abklemmen, aber für längere Intervalle erhalten Sie möglicherweise keine Mikrosekundenauflösung.

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

besser nutzen double:

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

Natürlich könnte man einfach eine timespec selbst verwenden:

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

Yup, versuchte ich den Code, und das einzige Mal, wenn ich ein negatives Ergebnis bekomme, ist, wenn ich den Float irrtümlich drucke value als int: 'printf ("% d ", timef)' Hier ist kein Fließkomma notwendig, es führt einfach so dumme Fehler. –

+0

Mein vollständiger Code schreibt Messungen in eine Datei (dataserver.txt und data.txt) und dann verarbeite ich sie mit Matlab, aber es ist leicht in Dateien ohne Verarbeitung zu sehen, dass es in der Serverdatei Messungen gibt, die größer sind als Messungen in der Clientdatei Negativ wird die Subtraktion Tt = Tclient-Tserver gemacht. Vielleicht ist der Fehler in Datei schreiben ... Wenn ich nach Hause zurückkomme, werde ich den vollständigen Code hier einfügen. Danke Jungs! – ampu

+0

Mit diesem Code bekomme ich größere Client-Maßnahmen, so bekomme ich nie negative Werte beim Subtrahieren von Server-Maß, aber ich bin nicht sicher, was die Formatnummer in beiden printf, weil ich Warnungen habe und ich nie % u.% 09lld Format gesehen habe before – ampu