#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netdb.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <time.h>
#include <sys/types.h>
#include <stdbool.h>
#define MAX_dani 0xF0000
struct params{ /* En esta estructura se almacenan los parametros de la funcion t*/
char web[20]; // Dominio web
int port; // Puerto (sera el 80, para peticiones HTTP)
int thread; // El numero de thread
int nrequests; // El numero de peticiones
int sleeptime; // El tiempo de espera entre cada peticion
};
int total_requests; // Para almacenar el numero total de peticiones
pthread_mutex_t lock; // Para evitar que varios threads modifiquen total_requests a la vez
int nthreads; // Numero de threads a crear
void* t(void *p) /* Esta es la funcion que va a ejecutar cada thread*/
{
int n = ((struct params*)p)->thread+1; // El numero de thread
printf("Proceso %i: presente\n", n
); // Presentacion char request[128]; // Para almacenar la peticion
_Bool connected; // Variable auxiliar, indica si el socket esta conectado
struct hostent *host = gethostbyname(((struct params*)p)->web); // Obtener la IP de la web
if(!host)
{
printf("Proceso %i: No se ha podido resolver la direccion del servidor\n", n
); return NULL;
}
printf("Proceso %i: Direccion IP(v4): %s\n", n
, inet_ntoa
(*((struct in_addr
*)host
->h_addr
))); /*Para getpeername()*/
struct sockaddr sockbuf;
int stsize = sizeof(sockbuf);
/*Preparar los datos de la conexion */
struct sockaddr_in sock;
sock.sin_family = AF_INET;
sock.sin_port = htons(((struct params*)p)->port);
sock.sin_addr.s_addr = inet_addr(inet_ntoa(*((struct in_addr *)host->h_addr)));
int sockfd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); // Creamos el socket
if(sockfd==-1)
{
printf("Proceso %i: No se pudo crear el socket\n", n
); return NULL;
}
printf("Proceso %i: Socket creado\n", n
); printf("Proceso %i: Conectando...\n", n
); int aux;
connect(sockfd, (struct sockaddr*) &sock, sizeof(struct sockaddr)); // Conectamos
printf("Proceso %i: Conectado\n", n
); connected=true;
sprintf(request
, "GET / HTTP/1.1\nHost: %s\nUser-Agent: Mozilla/4.0\n\n ", host
->h_name
); // Ponemos la peticion en una cadena printf("Proceso %i: Peticion en request\n", n
); for(aux=0; aux<(((struct params*)p)->nrequests); aux++)
{
if(getpeername(sockfd, &sockbuf, &stsize)<0) // Comprobar que el socket esta conectado
{
if(errno==ENOTCONN) // Si no lo esta, cerrar y reconectar
printf("Proceso %i: Reconectando socket...\n", n
); close(sockfd);
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if(connect(sockfd, (struct sockaddr*) &sock, sizeof(struct sockaddr))==-1)
{
connected=false;
break;
}
}
if(!connected) // Si no se pudo reconectar, decrementar aux y reiniciar el bucle
{
aux--;
continue;
}
write
(sockfd
, request
, strlen(request
)); // Hacer la peticion HTTP printf("Proceso %i: %i peticion/es\n", n
, aux
+1); pthread_mutex_lock(&lock); // Incrementar el numero total de peticiones
total_requests++;
pthread_mutex_unlock(&lock);
sleep(((struct params*)p)->sleeptime); // Pausar
}
close(sockfd); // Cerrar el socket
pthread_exit(NULL); // Salir
}
int main(int argc, char *argv[])
{
/*Tratamiento de linea de comandos*/
if(argc!=6)
{
printf("Uso: %s numero_de_threads dominio_web puerto(80) numero_de_peticiones_por_thread tiempo_de_espera\n", argv
[0]); }
/*Inicializar algunas estructuras y parametros*/
pthread_mutex_init(&lock, NULL);
pthread_t
*mythreads
= (pthread_t
*)malloc(atoi(argv
[1])*sizeof(pthread_t
)); pthread_attr_t a;
struct params
*p
= (struct params
*)malloc(atoi(argv
[1])*sizeof(struct params
)); int i, ret, j; // Algunas variables auxiliares
nthreads
= atoi(argv
[1]); // Numero de threads for(j=0; j<nthreads; j++)
{
p[j].thread = j;
p
[j
].
port = atoi(argv
[3]); p
[j
].
nrequests = atoi(argv
[4]); p
[j
].
sleeptime = atoi(argv
[5]); }
/*Setear la cantidad de memoria que un thread puede usar*/
pthread_attr_init(&a);
pthread_attr_setstacksize(&a, MAX_dani);
/*Saber el tiempo que hace que se inicio el programa*/
time_t start
=time(NULL
), end
; /*Crear los threads*/
for(i=0; i<nthreads; i++)
{
ret = pthread_create(&mythreads[i], &a, t, &p[i]);
switch(ret)
{
case 0:
printf("Thread %i creado\n", i
+1); break;
case EAGAIN:
_exit(1);
case EINVAL:
_exit(2);
case EPERM:
_exit(3);
}
}
/*Esperar a que terminen los threads, liberar memoria y mostrar algunas estadisticas aproximadas*/
pthread_attr_destroy(&a);
for(j=0; j<nthreads; j++)
pthread_join(mythreads[j], NULL);
pthread_mutex_destroy(&lock);
printf("Retornaron los hilos\n"); printf("Total de peticiones: %i\n", total_requests
); printf("Numero de peticiones por segundo: %lf\n", total_requests
/((double)(difftime(end
, start
)))); return 0;
}