Skip to content
Snippets Groups Projects
cliente.cpp 8.97 KiB
Newer Older
Leonardo's avatar
Leonardo committed
#include <netdb.h>
#include <netinet/in.h>
Leonardo's avatar
Leonardo committed
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/highgui/highgui_c.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <unistd.h>
#include <cstdio>

#define UDP_PORT 9998
#define TCP_PORT 9999
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define MAXLEN 1048576 //1024*1024

using namespace cv;

Leonardo's avatar
Leonardo committed
/** CONSTANTES Y CONFIGURACION **/
const char delimiter[] = "Grupo25";
Leonardo's avatar
Leonardo committed
const int keepAliveIntervalSeconds = 5;

// DEFINICION DE FUNCIONES
int printFrame(int received_data_size, char* recibido, int fin, char* buf);
void printFrameUDP(char* jpg, int size);
void TCP(const char* HOST);
void UDP(char* HOSTNAME);
int sendDatagramUDPtoHostname(int socket, char* HOSTNAME, char* buffer, unsigned short int destinationPort);
const char* getIP(char* hostname);
void error(const char *);
void* keepAliveMethod(void* ptr);

struct keepAliveData{
	int keepAliveId;
	int socketId;
	char* ip;
};


volatile sig_atomic_t flag = 0;
void my_function(int sig){ // can be called asynchronously
	flag = 1; // set flag
	sleep(1);
}


/**
 * Funcion auxiliar que retorna dentro del array indicando la posicion del comienzo del delimitador
 * array: arreglo a consultar
 * len: largo de array
 * delimiter: delimitador a buscar
 * inicio: desde que posicion arrancar a buscar
 */
int findPosDelimiter(const char *array, int len, int inicio) {
	int i = -1;
	int pos = 0;
	for (i = inicio; i<len; i++){
		if (sizeof(delimiter)-1 == pos)
			if (array[i] == delimiter[pos])
				return i - sizeof(delimiter) + 2;
			else
				pos=0;
		else
			if (array[i] == delimiter[pos])
				pos++;
			else
				pos=0;
	}
	return -1;
}

void TCP(const char* HOST){
	   int client_socket = socket(AF_INET, SOCK_STREAM, 0);

	   //obtenemos la direccion con getaddrinfo
	   struct addrinfo hints, *res;
	   memset(&hints, 0, sizeof hints);
	   hints.ai_family = AF_INET;
	   hints.ai_socktype = SOCK_STREAM;
	   getaddrinfo(HOST, STR(TCP_PORT), &hints, &res);

	   printf("Intentando conexion con %s:%d ...\n",HOST,TCP_PORT);
	   //primitiva CONNECT
	   if (connect(client_socket, res->ai_addr, res->ai_addrlen)<0){
		   printf("Error, imposible establecer conexion con el servidor.\n");
		   return;
	   }

	   //primitiva SEND
	   char msg[4];
	   sprintf(msg, "%s", "TCP");
	   msg[3] = '\0';

	   int msg_size = strlen(msg);
	   int sent_msg_size = send(client_socket, msg, msg_size, 0);
	   if (sent_msg_size == -1) {
		   printf("Error, imposible establecer conexion con el servidor.\n");
	   printf("Conexion establecida.\n");

	   char buf[MAXLEN]; // se almacenan los datos TCP recibidos en cada recv
	   char recibido[MAXLEN]; // mantiene el historico de datos recibidos, quitando los frames ya dibujados
	   int fin = 0; // Mantiene el indice del array recibido.
	   int received_data_size = 1;

	   {
		   int data_size = MAXLEN;
		   received_data_size = recv(client_socket, buf, data_size, 0);
		   fin = printFrame( received_data_size, recibido, fin, buf);
	   }

	   printf("Cerrando sockets a %s:%d\n", HOST, TCP_PORT);
	   close(client_socket);
	   freeaddrinfo(res);

}


int printFrame(int received_data_size, char* recibido, int fin, char* buf){
	   if (debug) {
		   printf("Datos recibidos: %d\n", received_data_size);
	   }
	   // en el arrray 'recibido' se mantiene los datos que ya exisitian mas los nuevos.
	   for(int j = 0; j < received_data_size; j++)
		   recibido[fin+j] = buf[j];

	   fin += received_data_size;
	   int inicio = 0;
	   int found = -1;
	   while ((found = findPosDelimiter(recibido, fin+1, inicio)) != -1) {
		   char jpg[found-inicio];
		   for (int h = 0; h < found-inicio; h++)
			   jpg[h] = recibido[inicio+h];

		   if (debug) {
			   printf("Nuevo jpeg size: %ui\n", sizeof(jpg));
		   }
		   namedWindow("cliente", CV_WINDOW_AUTOSIZE);
		   Mat rawData = Mat(1, found, CV_8UC1, jpg);
		   Mat frame = imdecode(rawData, CV_LOAD_IMAGE_COLOR);
		   imshow("cliente", frame);
Leonardo's avatar
Leonardo committed
		   waitKey(30);
	       inicio = found + sizeof(delimiter)-1;
	   }

	   if (inicio != 0) {
		   // mueve los datos recibidos al inicio, quitando el (o los) frame dibujado y el delimitador
		   for (int d = inicio; d < fin+1; d++)
			   recibido[d-inicio] = recibido[d];
		   fin -= inicio;
	   }
	   return fin;
}

void printFrameUDP(char* jpg, int size){
	   if (debug) {
		   printf("Nuevo jpeg size: %d\n", size);
	   }
	   namedWindow("cliente", CV_WINDOW_AUTOSIZE);
	   Mat rawData = Mat(1, size, CV_8UC1, jpg);
	   Mat frame = imdecode(rawData, CV_LOAD_IMAGE_COLOR);
	   imshow("cliente", frame);
	   waitKey(30);

}

void UDP(char* HOSTNAME){

	   unsigned int length;
	   struct from;

	   // CREATE SOCKET
	   int sock = socket(AF_INET, SOCK_DGRAM, 0);
	   if (sock < 0) error("error when creating socket");

	   char buffer[256];
	   bzero(buffer,256);
Leonardo's avatar
Leonardo committed
	   sprintf(buffer, "SUBSCRIPTION");

	   // ENVIO PEDIDO DE SUSCRIPCION
	   printf("Enviando Suscripcion a %s:%d ...\n", HOSTNAME, UDP_PORT); ::fflush(stdout);
	   if (sendDatagramUDPtoHostname(sock, HOSTNAME, buffer, UDP_PORT) < 0)
		   error("Error on send first datagram");

	   // ESPERO RESPUESTA DEL SERVIDOR
	   struct timeval timeout;
	   timeout.tv_sec = 5;
	   timeout.tv_usec = 0;
	   setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));

	   bzero(buffer,256);
	   struct sockaddr_in from;
	   if (recvfrom(sock,buffer,256,0,(struct sockaddr *)&from, &length) < 0){
		   if ((errno == EAGAIN) || (errno == EWOULDBLOCK)){
			   printf("Error, no hay respuesta del servidor.\n");
			   return;
		   }else{
			   printf("Error al recibir ACEEPT del servidor\n");
			   return;
		   }
	   }

	   if (debug) {
		   printf("Subscription: %s\n", buffer);
	   }

	   char* keepAliveId = new char[3];
	   keepAliveId[0] = buffer[9];
	   keepAliveId[1] = buffer[10];
	   keepAliveId[2] = '\0';

	   printf("keepAliveId is : %s\n", keepAliveId);

	   keepAliveData* kaData = new (keepAliveData);
	   kaData->keepAliveId = atoi(keepAliveId);
	   kaData->socketId = sock;
	   kaData->ip = new char[strlen(HOSTNAME)+1];
	   sprintf(kaData->ip, "%s" , HOSTNAME);
	   (kaData->ip)[strlen(HOSTNAME)] = '\0';

		pthread_t* hilos = new pthread_t[1];
	    pthread_create ( &hilos[0], NULL, keepAliveMethod, (void *)kaData );

	   char buf[MAXLEN]; // se almacenan los datos TCP recibidos en cada recv
	   int received_data_size = 1;

	   {
		   received_data_size = recvfrom( sock , buf , MAXLEN , 0 , (struct sockaddr *)&from , &length );
		   if (received_data_size < 1){
			   if ((received_data_size < 0) && ((errno == EAGAIN) || (errno == EWOULDBLOCK))){
					printf("Error, no hay respuesta del servidor.\n");
			   }else{
					printf("Error al recibir datos.\n");
		   }else {
			   printFrameUDP(buf, received_data_size);
		   }
	   }

	   //while (true)
	   //{
		//   memset ( frameBuffer , '\0' , 100 );
		//   if ( recvfrom( sock , frameBuffer , 100 , 0 , (struct sockaddr *)&from , &length ) < 0)
		//	  error("recv from UDP frames");
		//   printf("%s\n", frameBuffer);
	   //}
	   printf("Cerrando sockets a %s:%d, keepAliveId %s\n", HOSTNAME, UDP_PORT, keepAliveId);
	   close(sock);
}


void* keepAliveMethod(void* ptr){
	keepAliveData* kaData = (keepAliveData*)ptr;
	char* buffer = new char[13];
	sprintf(buffer, "KEEPALIVE:%d", kaData->keepAliveId);
	buffer[13] = '\0';
		sleep(keepAliveIntervalSeconds);
		printf("Sending keep alive request :%d\n", kaData->keepAliveId );
		sendDatagramUDPtoHostname(kaData->socketId, kaData->ip, buffer, UDP_PORT);
	}
}


int sendDatagramUDPtoHostname(int socket, char* HOSTNAME, char* buffer, unsigned short int destinationPort){
	   struct sockaddr_in server;
	   server.sin_family = AF_INET;
	   server.sin_addr.s_addr = inet_addr(getIP(HOSTNAME));
	   server.sin_port = htons(destinationPort);
	   return sendto( socket , buffer , strlen(buffer) , 0, (const struct sockaddr *)&server , sizeof(struct sockaddr_in) );
}


void error(const char *msg)
{
    perror(msg);
    exit(0);
}

const char* getIP(char* hostname){
	struct hostent *hp = gethostbyname(hostname);
	if (hp==0)
		error("Unknown host");
	char* ipAddress = NULL;
	struct in_addr **addr_list = (struct in_addr **)hp->h_addr_list;
    if(addr_list[0] != NULL){
    		int tam = strlen(inet_ntoa(*addr_list[0]));
    		ipAddress = new char[tam+1];
        sprintf(ipAddress, "%s", inet_ntoa(*addr_list[0]));
        ipAddress[tam] = '\0';
    }else{
    		error("Unknown host");
    }
	return ipAddress;
}

Leonardo's avatar
Leonardo committed
char* upCase(char* arg){
	char* s = arg;
	unsigned char c;
	while(*s){
		c = *s;
		*s = toupper(c);
		s++;
	}
	return arg;
}
int main(int argc, char *argv[]) {
	   // Register signals
	   signal(SIGINT, my_function);

Leonardo's avatar
Leonardo committed
	   if (strcmp(upCase(argv[1]),"TCP")  == 0){
Leonardo's avatar
Leonardo committed
	   }else if (strcmp(upCase(argv[1]),"UDP")  == 0){
		   printf("ERROR: primer argumento debe ser TCP o UDP.\n");