Em nossa busca pela elegância e simplicidade, vamos explorar o paradigma funcional ao criar um servidor HTTP em C, inspirado na modularidade do Nginx. Este servidor irá encantar os usuários com a magia de um arquivo de configuração e uma abordagem funcional.
Passo 1: Configurando o Projeto
Vamos começar criando um diretório chamado meu-servidor-c
e navegando até ele no terminal:
mkdir meu-servidor-c
cd meu-servidor-c
Passo 2: O Toque Mágico do Arquivo de Configuração
Vamos criar um arquivo chamado config.json
para adicionar um toque de magia ao nosso servidor. Abra-o e adicione o seguinte conteúdo:
{
"port": 8080,
"message": "Olá, este é o meu servidor HTTP funcional inspirado no Nginx!"
}
Passo 3: O Código Funcional em C
Vamos usar a biblioteca glib
para adotar uma abordagem mais funcional. Certifique-se de instalá-la antes de continuar:
sudo apt-get install libglib2.0-dev
Agora, podemos aprimorar nosso arquivo main.c
:
// main.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <glib.h>
#include <json-c/json.h>
#define BUFFER_SIZE 1024
typedef struct {
int port;
char* message;
} Config;
Config* read_config() {
FILE* file = fopen("config.json", "r");
if (!file) {
fprintf(stderr, "Erro ao abrir o arquivo de configuração.\\n");
exit(EXIT_FAILURE);
}
fseek(file, 0, SEEK_END);
long file_size = ftell(file);
rewind(file);
char* buffer = (char*)malloc(file_size + 1);
if (!buffer) {
fprintf(stderr, "Erro ao alocar memória para leitura do arquivo.\\n");
exit(EXIT_FAILURE);
}
fread(buffer, 1, file_size, file);
fclose(file);
buffer[file_size] = '\\0';
json_object* json = json_tokener_parse(buffer);
free(buffer);
Config* config = g_new0(Config, 1);
config->port = json_object_get_int(json_object_object_get(json, "port"));
config->message = g_strdup(json_object_get_string(json_object_object_get(json, "message")));
json_object_put(json);
return config;
}
void handle_request(int client_socket, Config* config) {
char response[BUFFER_SIZE];
snprintf(response, BUFFER_SIZE, "HTTP/1.1 200 OK\\nContent-Type: text/plain\\nContent-Length: %lu\\n\\n%s", strlen(config->message), config->message);
send(client_socket, response, strlen(response), 0);
}
void start_server(Config* config) {
int server_socket, client_socket;
struct sockaddr_in server_address, client_address;
// Criação do socket
server_socket = socket(AF_INET, SOCK_STREAM, 0);
// Configuração do endereço do servidor
memset(&server_address, 0, sizeof(server_address));
server_address.sin_family = AF_INET;
server_address.sin_addr.s_addr = INADDR_ANY;
server_address.sin_port = htons(config->port);
// Vinculação do socket ao endereço
bind(server_socket, (struct sockaddr*)&server_address, sizeof(server_address));
// Aguarda conexões
listen(server_socket, 5);
printf("Servidor funcional rodando em <http://localhost>:%d\\n", config->port);
while (1) {
// Aceitação de conexões
int client_address_len = sizeof(client_address);
client_socket = accept(server_socket, (struct sockaddr*)&client_address, (socklen_t*)&client_address_len);
// Processamento da requisição
handle_request(client_socket, config);
// Fechamento do socket do cliente
close(client_socket);
}
// Fechamento do socket do servidor
close(server_socket);
}
int main() {
Config* config = read_config();
start_server(config);
// Liberação de memória
g_free(config->message);
g_free(config);
return 0;
}
Conclusão Funcional e Elegante
Com a introdução de conceitos funcionais e a biblioteca glib
, nosso servidor HTTP em C assume uma abordagem mais elegante. A leitura do arquivo de configuração e o processamento de requisições agora refletem a simplicidade e expressividade da programação funcional.
Continue explorando o paradigma funcional, aprimorando suas habilidades em C e adicionando sua própria magia ao desenvolvimento de software. Lembre-se, a elegância está na simplicidade e na expressividade do código.
Top comments (0)