跳转至

serverhe

Github

仓库

结构

├───web服务器_updata/
   ├───makefile
   ├───conf/
      ├───main.conf
   ├───includes/
      ├───config.h
      ├───request.h
      ├───response.h
      ├───server.h
   ├───src/
      ├───config.c
      ├───main.c
      ├───request.c
      ├───response.c
      ├───server.c
   ├───static/
      ├───index.html

conf

main.conf

port = 8080
root_dir = root/static/index

src

congig.c

#include "config.h"

Config* parse_config(const char *config_file) {
    Config *config = (Config *)malloc(sizeof(Config));
    if (config == NULL) {
        printf("无法分配内存。\n");
        return NULL;
    }

    FILE *file = fopen(config_file, "r");
    if (file == NULL) {
        printf("无法打开配置文件。\n");
        free(config);
        return NULL;
    }

    char line[256];
    while (fgets(line, sizeof(line), file)) {
        char *key = strtok(line, "=");
        char *value = strtok(NULL, "\n");

        if (strcmp(key, "port") == 0) {
            config->port = atoi(value);
        } else if (strcmp(key, "root_dir") == 0) {
            strcpy(config->root_dir, value);
        }
    }

    fclose(file);
    return config;
}

main.c

#include<stdio.h>
#include<string.h>
#include <stdlib.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include "config.h"
#include "server.h"
#include "response.h"

// 定义main函数
int main() {
    // 定义配置文件路径
    const char *config_file = "conf/main.conf";

    // 解析配置文件
    Config *config = parse_config(config_file);
    if (config == NULL) {
        printf("无法解析配置文件。\n");
        return 1;
    }

    start_server(config->port,config->root_dir);
    return 0;


}
/*
    // 创建服务器套接字
    int server_socket = create_server_socket(config->port);
    if (server_socket == -1) {
        printf("无法创建服务器套接字。\n");
        free(config);
        return 1;
    }

    // 输出服务器正在监听的端口
    printf("Web服务器正在监听端口 %d...\n", config->port);

    // 使用while循环来接受客户端连接
    while (1) {
        int client_socket = accept_client_connection(server_socket);
        if (client_socket == -1) {
            printf("无法接受客户端连接。\n");
            continue;
        }

        // 处理客户端请求
        handle_request(client_socket, config->root_dir);

        // 关闭客户端套接字
        close(client_socket);
    }

    // 关闭服务器套接字并释放配置内存
    close(server_socket);
    free(config);
    return 0;
}
*/

/*
#include "server.h"

int main() {

    int port = 7890; // 监听端口
    start_server(port);
    return 0;
}
*/


/*
web_server/
|-- src/
|   |-- main.c       // 主函数入口
|   |-- server.c     // 服务器核心逻辑
|   |-- request.c    // 请求处理逻辑
|   |-- response.c   // 响应生成逻辑
|-- includes/
|   |-- server.h     // 服务器相关函数声明
|   |-- request.h    // 请求处理函数声明
|   |-- response.h   // 响应生成函数声明
|-- static/
|   |-- index.html   // 默认返回的HTML页面
|-- Makefile         // 编译规则

*/

//编译:gcc -Wall -g -o web_server src/main.c src/server.c src/request.c src/response.c -Iincludes

request.c

/*#include "request.h"
#include "response.h"
#include "server.h"

void handle_request(int client_socket, const char *root_dir) {
    send_response(client_socket, root_dir);
}
*/

#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/socket.h>
#include "response.h"
#include "config.h"

void handle_request(int client_socket) {

        // 定义配置文件路径
    const char *config_file = "conf/main.conf";

    // 解析配置文件
    Config *config = parse_config(config_file);


    char buffer[1024] = {0};
    ssize_t bytes_read = recv(client_socket, buffer, sizeof(buffer) - 1, 0);

    if (bytes_read > 0) {
        // 这里可以添加解析HTTP请求的逻辑,但为了简洁,我们直接发送响应

        send_response(client_socket,config->root_dir);
    }
}

response.c

#include "response.h"
#include<stdio.h>
#include<string.h>
#include <stdlib.h>

void send_response(int client_socket, const char *root_dir) {
    char index_html_path[256];
    sprintf(index_html_path, "%s/index.html", root_dir);

    FILE *file = fopen(index_html_path, "r");
    if (file == NULL) {
        printf("无法打开文件以读取内容。\n");
        return;
    }

    char html_content[4096] = {0};
    size_t bytes_read = fread(html_content, sizeof(char), sizeof(html_content) - 1, file);
    if (bytes_read == 0) {
        printf("无法读取文件内容。\n");
        fclose(file);
        return;
    }

    html_content[bytes_read] = '\0';
    fclose(file);

    char header[512] = {0};
    sprintf(header, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: %zu\r\n\r\n", strlen(html_content));

    send(client_socket, header, strlen(header), 0);
    send(client_socket, html_content, strlen(html_content), 0);
}

/*
#include<stdio.h>
#include<string.h>
#include <unistd.h>
#include <sys/socket.h>

void send_response(int client_socket) {
    const char* html_content = "<!DOCTYPE html><html><head<title>Hello from C Web Server</title></head><body><h1>Hello, World!</h1></body></html>";
    char header[512] = {0};

    // 构建HTTP响应头
    sprintf(header, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\nContent-Length: %zu\r\n\r\n", strlen(html_content));


    // 发送响应头和内容
    send(client_socket, header, strlen(header), 0);
    send(client_socket, html_content, strlen(html_content), 0);
}

// 在response.h中声明send_response函数
void send_response(int client_socket);
*/

server.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h> 
#include <sys/socket.h>
#include "request.h"
#include "response.h"

void start_server(int port,const char *root_dir ) {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int opt = 1;
    int addrlen = sizeof(address);


    // 创建socket文件描述符
    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("socket failed");
        exit(EXIT_FAILURE);
    }


    // 设置socket选项,允许端口复用
    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt))) {
        perror("setsockopt");
        exit(EXIT_FAILURE);
    }

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


      // 绑定地址到socket
    if (bind(server_fd, (struct sockaddr *)&address, sizeof(address))<0) {
        perror("bind failed");
        exit(EXIT_FAILURE);
    }

    // 开始监听,最大连接数为5
    if (listen(server_fd, 5) < 0) {
        perror("listen");
        exit(EXIT_FAILURE);
    }

    while(1) {
        // 接受新的连接请求
        if ((new_socket = accept(server_fd, (struct sockaddr *)&address, (socklen_t*)&addrlen))<0) {
            perror("accept");
            exit(EXIT_FAILURE);
        }

           // 处理客户端请求
        handle_request(new_socket);

        close(new_socket); // 关闭连接
    }

    shutdown(server_fd, SHUT_RDWR);
}

includes

config.h

#ifndef CONFIG_H
#define CONFIG_H

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

typedef struct {
    int port;
    char root_dir[256];
} Config;

Config* parse_config(const char *config_file);

#endif // CONFIG_H

request.h

#ifndef REQUEST_H
#define REQUEST_H

#include <unistd.h>
#include <sys/socket.h>

void handle_request(int client_socket);

#endif // REQUEST_H

response.h

#ifndef RESPONSE_H
#define RESPONSE_H

#include <unistd.h>
#include <sys/socket.h>

void send_response(int client_socket, const char *root_dir);

#endif // RESPONSE_H

server.h

#ifndef SERVER_H
#define SERVER_H

#include <unistd.h>
#include <sys/socket.h>

int create_server_socket(int port);
void start_server(int server_socket, const char *root_dir);

#endif // SERVER_H