在這篇部落格文章中,我們將探索如何用 C 語言建立一個可以提供 HTML 檔案的簡單 TCP 伺服器。我們將分解程式碼,解釋其工作原理,並討論增強該專案的未來計劃。這是一個很好的例子,說明瞭如何在 C 中「只做事情」而不會使過程過於複雜!
專案的目標是實作一個基本的 TCP 伺服器,用於偵聽客戶端連線並根據請求提供 HTML 檔案。伺服器將處理客戶端請求,讀取指定的 HTML 文件,並將內容作為 HTTP 回應傳送回客戶端。
為了組織我們的程式碼,我們將按如下方式建立專案:
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
首先,讓我們建立一個實用程式檔案來處理套接字初始化。這將確保我們的主伺服器程式碼保持乾淨和專注。
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; }
接下來,我們將建立一個服務 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; }
現在,讓我們實作處理傳入客戶端請求的邏輯。
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; }
最後,讓我們將所有內容放在主文件中。
src/main.c
展望未來,我們計劃實施多項增強功能和功能:
這個簡單的 TCP 伺服器專案作為如何用 C 建立 Web 伺服器的基礎範例,展示了該語言的強大功能和簡單性。透過在此基礎上構建,我們可以開發更複雜的功能並提高效能,使其成為服務 Web 內容的強大解決方案。
您可以在 GitHub 上找到完整的原始程式碼並為該專案做出貢獻:GitHub 儲存庫連結。
請隨時提供回饋、提出問題或為未來的改進貢獻您的想法!
以上是用 C 語言建立一個簡單的 TCP 伺服器的詳細內容。更多資訊請關注PHP中文網其他相關文章!