sábado, 2 de junho de 2012

multithreaded client em C

Olá pessoal, hoje vamos implementar um cliente multithread em C. Na verdade ele não faz muita coisa, mas o objetivo é gerar um número de conexões que irão ou não se desconectar do servidor, ou seja, pode funcionar como um programa teste para o seu servidor.

Para facilitar o nosso entendimento, vamos dividir nosso projeto em arquivos. Nosso arquivos serão os seguintes:
Para funções de entrada de dados e nossos tipos:
Data.c
Data.h

Para nossas funções de rede:
Functions.c
Functions.h

Nosso programa principal:
main.c

Nosso makefile
Makefile

===========================Data.h========================================

#ifndef DATA_H
#define DATA_H

typedef enum op
{
CONNECTTERMINATE = 1,
CONNECTWAIT
} Eoptions;

typedef struct configurations{
int numberOfConnections;
char * ip;
int port;
Eoptions opConf;
int socketId;
}config;

int splitOptions(char ** input, config * settings);
#endif

===========================Data.c========================================
#include<string.h>
#include<stdlib.h>
#include"Data.h"
#include<stdio.h>

int printSettings(config * settings){
if(settings == NULL){
return -1;
}
printf("\n\tNumber of Connections: %d", settings->numberOfConnections);
printf("\n\tIP of server: %s", settings->ip);
printf("\n\tPort of server: %d", settings->port);
printf("\n\tConnections options: %d",settings->opConf);
return 1;
}

int splitOptions(char ** input, config * settings){

if(input == NULL)
return 0;
if(settings == NULL)
return 0;
settings->numberOfConnections = atoi(input[1]);
settings->ip = input[2];
settings->port = atoi(input[3]);
settings->opConf = atoi(input[4]);
//Enable to debug
//printSettings(settings);

return 1;
}

===========================Functions.h=====================================

#ifndef FUNCTIONS_H
#define FUNCTIONS_H
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include "Data.h"



void setLocal(struct sockaddr_in * clientAddr);
void setRemote(struct sockaddr_in * serverAddr, char* serverIp, int port);
void  mainClient(config* settings);


#endif

===========================Functions.c=====================================
#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <string.h>
#include "Functions.h"
#include <arpa/inet.h>
#include <unistd.h>
#include <string.h>

int sendStr(config * settings, char * message){
char buffer[255];
if(settings == NULL)
return -1;
strcpy(buffer,message);
send(settings->socketId,buffer,strlen(buffer),0);

return 1;
}

void setLocal(struct sockaddr_in * clientAddr){
memset((void *) clientAddr, 0, sizeof(struct sockaddr_in));
if(clientAddr==NULL){
printf("\n\tClient struct is null in setLocal");
}
clientAddr->sin_family = AF_INET;
clientAddr->sin_addr.s_addr = INADDR_ANY;
clientAddr->sin_port = 0;

}

void setRemote(struct sockaddr_in * serverAddr, char* serverIp, int port){
serverAddr->sin_family = AF_INET;
serverAddr->sin_addr.s_addr = inet_addr(serverIp);
serverAddr->sin_port = htons(port);


}

void mainClient(config * settings){
struct sockaddr_in clientAddr, serverAddr;
int sock;
setLocal(&clientAddr); //local settings
setRemote(&serverAddr,settings->ip,settings->port);
sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
settings->socketId = sock;
bind(sock, (const struct sockaddr *) &serverAddr, sizeof(serverAddr));
printf("\n\tConnecting");
if (connect(sock, (const struct sockaddr *) &serverAddr, sizeof(serverAddr)) != 0) {
perror("client");
return;
}

if(settings->opConf == CONNECTTERMINATE){
sendStr(settings, "I will close in ten seconds");

sleep(10);
close(sock);
}
else{
sendStr(settings, "I will never close");
while(1){

sleep(10);
}
}

}

===========================main.c=====================================
#include<stdio.h>
#include<pthread.h>
#include"Functions.h"
#include"Data.h"

int main(int argc, char** argv){
config settings;
int cont;
pthread_t thread[10];
if(argc != 5){
printf("\n\tInvalid options.");
printf("\n\tUsage: MultiThreadClient Ncon IP Port option");
printf("\n\tNcon - Number of connections");
printf("\n\tIP - Server IP");
printf("\n\tPort - Port server is listening");
printf("\n\tOption: \n\t1: connect and terminate\n\t2: connect and never terminate");
return 0;
}

if(splitOptions(argv, &settings) == 0)
return 0;
for(cont = 0; cont < settings.numberOfConnections; cont++){
printf("\n\tCreatingthread: %d", cont);
pthread_create( &thread[cont], NULL,(void*) &mainClient , (void *)&settings);
}
printf("\n\tPress a key");
getchar();
return 1;
}

===========================Makefile=====================================
CC=gcc
CFLAGS=-W -Wall -g
SRC= $(wildcard *.c)
OBJ= $(SRC:.c=.o)

all: clean $(OBJ)
gcc -o MultiThreadClient $(OBJ) -lpthread
%.o: %.c
@$(CC) -o $@ -c $< $(CFLAGS)
clean:
rm -f *.o 

Para executar:
./MultiThreadClient 8 127.0.0.1 4001 1

ou
./MultiThreadClient 8 127.0.0.1 4001 2

Estamos assumindo que você possui um server em seu pc local escutando na porta 4001.