首頁  >  文章  >  後端開發  >  用 C 語言建立一個簡單的 TCP 伺服器

用 C 語言建立一個簡單的 TCP 伺服器

DDD
DDD原創
2024-11-04 07:16:01752瀏覽

Building a Simple TCP Server in C

在這篇部落格文章中,我們將探索如何用 C 語言建立一個可以提供 HTML 檔案的簡單 TCP 伺服器。我們將分解程式碼,解釋其工作原理,並討論增強該專案的未來計劃。這是一個很好的例子,說明瞭如何在 C 中「只做事情」而不會使過程過於複雜!

項目概況

專案的目標是實作一個基本的 TCP 伺服器,用於偵聽客戶端連線並根據請求提供 HTML 檔案。伺服器將處理客戶端請求,讀取指定的 HTML 文件,並將內容作為 HTTP 回應傳送回客戶端。

?在 Twitter(X) 上繼續對話:@trish_07

? GitHub 儲存庫:探索 TCP 伺服器專案儲存庫

專案結構

為了組織我們的程式碼,我們將按如下方式建立專案:

tcp_server_c/
├── CMakeLists.txt             # Build configuration
├── include/
│   ├── server.h               # Main server header file
│   ├── html_serve.h           # Header for serve_html function
│   ├── request_handler.h      # Header for handle_client function
│   └── socket_utils.h         # Header for socket utility functions
├── src/
│   ├── server.c               # Main server program
│   ├── html_serve.c           # serve_html function
│   ├── request_handler.c      # handle_client function
│   └── socket_utils.c         # Utility functions for socket operations
└── README.md                  # Project documentation

代碼分解

1. 套接字實用程式

首先,讓我們建立一個實用程式檔案來處理套接字初始化。這將確保我們的主伺服器程式碼保持乾淨和專注。

include/socket_utils.h

#ifndef SOCKET_UTILS_H
#define SOCKET_UTILS_H

#include <arpa/inet.h>

int initialize_server(struct sockaddr_in* address);

#endif

src/socket_utils.c

#include "socket_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define PORT 8080

int initialize_server(struct sockaddr_in* address) {
    int server_fd;
    int opt = 1;

    if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0) {
        perror("Socket failed!");
        return -1;
    }

    if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt)) != 0) {
        perror("setsockopt failed");
        close(server_fd);
        return -1;
    }

    address->sin_family = AF_INET;
    address->sin_addr.s_addr = INADDR_ANY;
    address->sin_port = htons(PORT);

    if (bind(server_fd, (struct sockaddr*)address, sizeof(*address)) < 0) {
        perror("Bind failed!");
        close(server_fd);
        return -1;
    }

    if (listen(server_fd, 3) < 0) {
        perror("Listen failed!");
        close(server_fd);
        return -1;
    }

    return server_fd;
}

2. HTML 服務功能

接下來,我們將建立一個服務 HTML 檔案的函數。此函數將讀取 HTML 檔案的內容並將其傳回給呼叫者。

include/html_server.h

#ifndef HTML_SERVER_H
#define HTML_SERVER_H

char* serve_html(const char* filename);

#endif

src/html_server.c

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

char* serve_html(const char* filename) {
    FILE* file = fopen(filename, "r");
    if (!file) {
        perror("Error opening file");
        return NULL;
    }

    fseek(file, 0, SEEK_END);
    long length = ftell(file);
    fseek(file, 0, SEEK_SET);

    char* buffer = malloc(length + 1);
    if (!buffer) {
        perror("Error allocating memory");
        fclose(file);
        return NULL;
    }

    fread(buffer, 1, length, file);
    buffer[length] = '<pre class="brush:php;toolbar:false">#ifndef REQUEST_HANDLER_H
#define REQUEST_HANDLER_H

#include <sys/socket.h>

void handle_client(int new_socket);

#endif
'; // Null-terminate the buffer fclose(file); return buffer; }

3. 處理客戶請求

現在,讓我們實作處理傳入客戶端請求的邏輯。

include/request_handler.h

#include "request_handler.h"
#include "html_server.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>

#define BUFFER_SIZE 1024

void handle_client(int new_socket) {
    char buffer[BUFFER_SIZE] = { 0 };
    read(new_socket, buffer, BUFFER_SIZE);

    // Serve the HTML file
    char* html_content = serve_html("../html/index.html");
    if (html_content) {
        write(new_socket, "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n", 48);
        write(new_socket, html_content, strlen(html_content));
    } else {
        const char* not_found_response = "HTTP/1.1 404 Not Found\r\nContent-Type: text/html\r\n\r\n<h1>404 Not Found</h1>";
        write(new_socket, not_found_response, strlen(not_found_response));
    }

    free(html_content);
    close(new_socket); // Close the connection with the current client
}

src/request_handler.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "socket_utils.h"
#include "request_handler.h"

int main() {
    int server_fd, new_socket;
    struct sockaddr_in address;
    int addrlen = sizeof(address);

    server_fd = initialize_server(&address);
    if (server_fd == -1) {
        return EXIT_FAILURE;
    }

    printf("Server listening on port: 8080\n");

    while (1) {
        if ((new_socket = accept(server_fd, (struct sockaddr*)&address, (socklen_t*)&addrlen)) < 0) {
            perror("Connection not accepted!");
            continue;
        }
        handle_client(new_socket); // Handle the client request
    }

    close(server_fd);
    return 0;
}

4. 主伺服器邏輯

最後,讓我們將所有內容放在主文件中。

src/main.c

未來計劃

展望未來,我們計劃實施多項增強功能和功能:

  1. 多執行緒支援:為了同時處理多個客戶端連接,我們將引入執行緒功能來提高伺服器的效率。
  2. 動態內容服務:透過與輕量級模板引擎整合來實現提供動態內容的功能。
  3. 日誌記錄:新增日誌記錄機制來追蹤請求、錯誤和伺服器效能。
  4. 安全功能:探索新增 HTTPS 支援和輸入驗證以增強安全性。
  5. 改進的錯誤處理:針對各種場景實現更好的錯誤處理,例如檔案未找到、伺服器過載等

結論

這個簡單的 TCP 伺服器專案作為如何用 C 建立 Web 伺服器的基礎範例,展示了該語言的強大功能和簡單性。透過在此基礎上構建,我們可以開發更複雜的功能並提高效能,使其成為服務 Web 內容的強大解決方案。

您可以在 GitHub 上找到完整的原始程式碼並為該專案做出貢獻:GitHub 儲存庫連結。

請隨時提供回饋、提出問題或為未來的改進貢獻您的想法!


以上是用 C 語言建立一個簡單的 TCP 伺服器的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn