• Revista PROGRAMAR: Já está disponível a edição #53 da revista programar. Faz já o download aqui!

NoOne

[C] Servidor simples de HTTP

6 mensagens neste tópico

Este foi um trabalho que tive que realizar para a cadeira de redes dos computadores, não está super completo mas dá para começar a perceber Sockets em C...

Algumas das coisas que faltam neste programa são:

- A implementação de alguns métodos, mas principlamente do método POST.

- Mais alguma informação nos cabeçalhos, principalmente Content-Size.

E talvez algumas outras falhas que não me tenha apercebido.

Não sei se alguém achará isto útil, mas aqui fica:

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

//sockets
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/stat.h>


//semaforos
#include <sys/ipc.h>
#include <sys/sem.h>

#define tipoData "%a, %d/%m/%Y %H:%M:%S"
#define nMesAno "%m_%Y"
#define SERVER "RCOMP 2007/2008"

char *extensao(char *nome)
{
 char *ext = strrchr(nome, '.');
 if (!ext) return NULL;
 if (strcmp(ext, ".html") == 0 || strcmp(ext, ".htm") == 0) return "text/html";
 if (strcmp(ext, ".jpg") == 0 || strcmp(ext, ".jpeg") == 0) return "image/jpeg";
 if (strcmp(ext, ".gif") == 0) return "image/gif";
 if (strcmp(ext, ".png") == 0) return "image/png";
 if (strcmp(ext, ".css") == 0) return "text/css";
 if (strcmp(ext, ".au") == 0) return "audio/basic";
 if (strcmp(ext, ".wav") == 0) return "audio/wav";
 if (strcmp(ext, ".avi") == 0) return "video/x-msvideo";
 if (strcmp(ext, ".mpeg") == 0 || strcmp(ext, ".mpg") == 0) return "video/mpeg";
 if (strcmp(ext, ".mp3") == 0) return "audio/mpeg";
 return NULL;
}

void enviarCabecalho(char *estado, char *titulo, char *ext, char *protocolo,int newSock)
{
char cabecalho[500];
time_t now;
char timebuf[128];
now = time(NULL);
strftime(timebuf, sizeof(timebuf), tipoData, gmtime(&now));			

strcpy(cabecalho, protocolo);
strcat(cabecalho, " ");
strcat(cabecalho, estado);
strcat(cabecalho, " ");
strcat(cabecalho, titulo);
strcat(cabecalho, "\r\n");

strcat(cabecalho, "Data:");
strcat(cabecalho, timebuf);
strcat(cabecalho, "\r\n");

strcat(cabecalho, "Server: ");
strcat(cabecalho, SERVER);
strcat(cabecalho, "\r\n");

if (ext)
{
	strcat(cabecalho, "Content-Type: ");
	strcat(cabecalho, ext);
	strcat(cabecalho, "\r\n");
}

strcat(cabecalho, "Connection: close\r\n");
strcat(cabecalho, "\r\n");
write(newSock, cabecalho, strlen(cabecalho));
printf("\n%s",cabecalho);
}

void enviarErro(char *estado, char *titulo, char *texto, char *protocolo, int newSock)
{
enviarCabecalho(estado, titulo, "text/html",  protocolo, newSock);
char msgErro[500];

strcpy(msgErro, "<HTML><HEAD><title>");
strcat(msgErro, estado);
strcat(msgErro, " ");
strcat(msgErro, titulo);
strcat(msgErro, "</titulo></HEAD>\r\n");
strcat(msgErro, "<BODY><H4>");
strcat(msgErro, estado);
strcat(msgErro, " ");
strcat(msgErro,  titulo);
strcat(msgErro, "</H4>\r\n");
strcat(msgErro,  texto);
strcat(msgErro, "\r\n");
strcat(msgErro, "</BODY></HTML>\r\n");
write(newSock, msgErro, strlen(msgErro));
printf("%s",msgErro);
}

int ligarSocket(int port)
{
int sock;
struct sockaddr_in endServidor;
int adl=sizeof(endServidor);
// Criar Socket
sock = socket(AF_INET, SOCK_STREAM, 0);
//Verificar se socket foi criado correctamente
if(sock<0) {
   	perror("Não consegue abrir socket");
    return 1;
 	}

endServidor.sin_family = AF_INET;
endServidor.sin_addr.s_addr = htonl(INADDR_ANY);
endServidor.sin_port = htons(port);

//Utilizar Porta escolhida para o servidor
if(bind(sock,(struct sockaddr *)&endServidor,adl)<0)
{
	close(sock);
	puts("Porta de servidor ocupada...");
	exit(1);
}	
return sock;
}

int escreverLogs(char * textoLog)
{
time_t now;
char timebuf[128];
now = time(NULL);
strftime(timebuf, sizeof(timebuf), nMesAno, gmtime(&now));
char nomeFicheiro[10] = "log";
strcat(nomeFicheiro,timebuf);
strcat(nomeFicheiro,".txt");
printf("%s\n",textoLog);

FILE *logs = fopen(nomeFicheiro, "a+");
if(logs==NULL) return -1;
fwrite(textoLog, 1, strlen(textoLog), logs);
fclose(logs);
return 0;
}

int criarSemaforo()
{
int sem;
union semun {int val;} arg;
if( (sem=semget(13372, 1, IPC_CREAT|IPC_EXCL|0777)) == -1 )	
{
	printf("Erro a criar semaforo\n");
	return -1;
}
//recursos disponiveis:
arg.val=1;
if( semctl(sem,0,SETVAL,arg) == -1 )
{
	printf("Erro a atribuir recursos a semaforo!\n");
	return -1;
}
return sem;
}

int main(int argc, char *argv[])
{

pid_t proc;
int contProcessos=0;
int erroFicheiro=0;
int sock,newSock, s, port=9889,i=0,sem;

static struct sembuf up, down;
   up.sem_op=1;
   down.sem_op=-1;

char dados[4096];
char linha[255];
char *metodo;
char *caminho;

char log[200];

//Possibilidade de receber porta como para metro
if (argc == 2)
	port = atoi(argv[1]);

//Funçao que cria e liga ao socket
sock=ligarSocket(port);


//Criar semaforo para controlar acesso aos logs
sem=criarSemaforo();
if(sem==-1) return 0;

//receber pedido de conecções...
listen(sock,5); //5 é o numero máximo de pedidos atendidos....

//Ciclo infinito
while(1) {
    printf("   À espera de ligação na porta %u\n\n",port);	


    newSock = accept(sock, NULL, NULL);
   	if(newSock<0) {
      printf("Não consegue ligar ");
      return 1;
   	}

	//Ler pedido
	read(newSock, linha,255);
	contProcessos++;

	//Criar um processo para tratar do pedido
	proc=fork();
	if(proc<0)
	{
		printf("Erro na criação do processo\n");
	}
	//Filho:
	else if(proc==0)
	{	
		printf("Pedido recebido e a ser tratado pelo filho %d\n\n",contProcessos);

		char protocolo[9],pedido[256];
		strcpy(pedido,linha);

		//extrair metodo caminho e protocolo do pedido recebido
	    metodo = strtok(linha, " ");
		caminho = strtok(NULL, " ");
	    protocol = strtok(NULL, "\r");	

		if (!metodo || !caminho || !protocolo) return -1;
		printf("----------------------------------\n");
		printf("Metodo: %s \n",metodo);
		printf("Caminho: %s \n",&caminho[1]);
		printf("Protocolo: %s \n",protocolo);
		printf("Tipo de Ficheiro: %s \n",extensao(caminho));
		printf("----------------------------------\n");

		//directorio
		if(strcmp(&caminho[strlen(caminho)-1],"/")==0)
			strcat(caminho,"index.html");

		FILE *ficheiro = fopen(&caminho[1], "r");

		//verificar se metodo é valido, tem que ser GET com maiusculas
		if (strcmp(metodo, "GET") == 0)
		{				
			if (!ficheiro)
			{
				printf("Ficheiro nao encontrado, a enviar mensagem de erro.... \n \n");
				enviarErro("404", "Not Found",  "Ficheiro não encontrado.",protocolo,newSock);
				printf("Erro Enviado... \n");
				shutdown(newSock,1);
				close(newSock);
				exit(-1);
			}
			else
			{
				//Ler Ficheiro
				printf("\n   A enviar resposta...\n");
				enviarCabecalho("200", "OK",  "Página Carregada.",protocolo,newSock);
				while ((erroFicheiro = fread(dados, 1, sizeof(dados), ficheiro)) > 0)
					write(newSock, dados, erroFicheiro);	
				fclose(ficheiro);

				time_t now;
				char timebuf[128];
				now = time(NULL);
				strftime(timebuf, sizeof(timebuf), tipoData, gmtime(&now));

				//Escrever pedido nos logs
				strcpy(log, "\r\n --------------------------------------------------------------------------");
				strcat(log, "\r\n Data: ");
				strcat(log, timebuf);
				strcat(log, "\r\nMetodo: ");
				strcat(log, metodo);
				strcat(log, " | Caminho: ");
				strcat(log, caminho);
				strcat(log, " | protocolo: ");
				strcat(log, protocolo);
				strcat(log, "\r\n --------------------------------------------------------------------------");

				//Controlar apenas um processo a escrever no ficheiro de cada vez !
				semop(sem,&down,1);
					if(escreverLogs(log)==-1)
					{
						printf("Impossivel abrir ficheiro logs.txt\n");
						return -1;
					}
				semop(sem,&up,1);

				printf("\n   Enviado...\n");
			}
		}
		else if (strcmp(metodo, "HEAD") == 0)
		{

			if (!ficheiro)
				enviarCabecalho("404", "Not Found",  "Ficheiro não encontrado.",protocolo,newSock);
			else
				enviarCabecalho("200", "OK",  "Página Carregada.",protocolo,newSock);

		} else if (strcmp(metodo, "POST") == 0)
		{	

			printf("%s\n",pedido);

		} else
		{
			enviarErro("501", "Not supported", "Method is not supported.",protocolo, newSock);
			return -1;
		}
		printf("\n----------------------- Fim de sessão ------------------\n\n");
		shutdown(newSock,1);
		close(newSock);
		exit(0);
	}

 	}

return 0;
}

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boa tarde,

Será que podes disponibilizar o codigo do cliente?...

Seria muito útil..

Aguardo..

Cumps

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Nossa... Muito bom mesmo! Irei usar bem esse código para meu aprendizado!

Vlw!

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Boa tarde,

Será que podes disponibilizar o codigo do cliente?...

Seria muito útil..

Aguardo..

Cumps

O código de cliente de um servidor HTTP é o browser... Safari, Firefox, Opera, IE, Chrome, etc.

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Qual foi o programa utilizado para compilar? é que o dev-c++ não tem metade das lib

0

Partilhar esta mensagem


Link para a mensagem
Partilhar noutros sites

Crie uma conta ou ligue-se para comentar

Só membros podem comentar

Criar nova conta

Registe para ter uma conta na nossa comunidade. É fácil!


Registar nova conta

Entra

Já tem conta? Inicie sessão aqui.


Entrar Agora