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(
^
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;' –