Construindo Elegância Funcional em C: Servidor HTTP Inspirado no Nginx
Published: 2023-12-27 14:18:56

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:

```bash
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:

```json
{
  "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:

```bash
sudo apt-get install libglib2.0-dev

```

Agora, podemos aprimorar nosso arquivo `main.c`:

```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.