在 Ubuntu 虛擬機中實現 HTML 表單與 C 語言 HTTP 服務器交互

一、環境說明

  • 系統:Ubuntu 虛擬機(已安裝基本開發工具,如 GCC)
  • 目標:通過 C 語言服務器托管 HTML 表單頁面,并實現數據提交交互

二、核心文件準備

1. 創建 HTML 表單頁面(xunfei.html

<!-- 保存路徑:~/Linux-HTTP/xunfei.html -->
<html lang="zh-CN">
<head><meta charset="utf-8"><title>訊飛課堂表單</title>
</head>
<body><div style="text-align:center; height:500px"><h2>歡迎來到訊飛課堂!</h2><form action="/commit" method="post">姓名:<input type="text" name="name" required><br><br>年齡:<input type="text" name="age" required><br><br><button type="submit">提交</button></form></div>
</body>
</html>
  • 關鍵點
    • action="/commit":表單數據通過 POST 請求發送到服務器?/commit?路徑
    • method="post":使用 POST 方法提交數據(適合傳輸敏感或大量數據)

2. 編寫 C 語言 HTTP 服務器代碼(server.c

// 保存路徑:~/Linux-HTTP/server.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/epoll.h>
#include <fcntl.h>#define PORT 8080          // 服務器端口
#define BUFFER_SIZE 4096   // 緩沖區大小
#define MAX_EVENTS 1000    // 最大事件數// 設置套接字為非阻塞模式
void set_nonblocking(int fd) {int flags = fcntl(fd, F_GETFL);fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}// 發送 HTTP 響應
void send_response(int client_fd, const char *status, const char *content_type, const char *content, size_t len) {char header[BUFFER_SIZE];snprintf(header, BUFFER_SIZE,"HTTP/1.1 %s\r\n""Content-Type: %s\r\n""Content-Length: %zu\r\n""Connection: close\r\n\r\n",status, content_type, len);write(client_fd, header, strlen(header));write(client_fd, content, len);
}// 處理請求
void handle_request(int client_fd) {char buffer[BUFFER_SIZE] = {0};ssize_t bytes_read = read(client_fd, buffer, BUFFER_SIZE - 1);if (bytes_read <= 0) return;// 解析請求行(Method、Path、Protocol)char *method = strtok(buffer, " ");char *path = strtok(NULL, " ");char *protocol = strtok(NULL, "\r\n");// 處理 GET 請求(返回 HTML 頁面)if (strcmp(method, "GET") == 0) {char file_path[256] = "./xunfei.html";if (strcmp(path, "/") == 0) {  // 根路徑映射到表單頁面FILE *file = fopen(file_path, "r");if (!file) {send_response(client_fd, "404 Not Found", "text/plain", "File Not Found", 14);return;}fseek(file, 0, SEEK_END);long file_size = ftell(file);fseek(file, 0, SEEK_SET);char *content = malloc(file_size);fread(content, 1, file_size, file);fclose(file);send_response(client_fd, "200 OK", "text/html", content, file_size);free(content);}}// 處理 POST 請求(接收表單數據)else if (strcmp(method, "POST") == 0 && strstr(path, "/commit")) {char *body = strstr(buffer, "\r\n\r\n") + 4;  // 提取請求體printf("接收到表單數據:%s\n", body);send_response(client_fd, "200 OK", "text/plain", "提交成功", 9);}else {send_response(client_fd, "501 Not Implemented", "text/plain", "不支持的方法", 12);}close(client_fd);
}int main() {// 創建 socketint server_fd = socket(AF_INET, SOCK_STREAM, 0);if (server_fd < 0) {perror("socket創建失敗");exit(1);}// 綁定端口struct sockaddr_in addr = {.sin_family = AF_INET,.sin_port = htons(PORT),.sin_addr.s_addr = INADDR_ANY};if (bind(server_fd, (struct sockaddr*)&addr, sizeof(addr)) < 0) {perror("bind失敗");close(server_fd);exit(1);}// 監聽連接if (listen(server_fd, SOMAXCONN) < 0) {perror("listen失敗");close(server_fd);exit(1);}printf("服務器啟動,監聽端口 %d...\n", PORT);// 使用 epoll 處理并發連接int epoll_fd = epoll_create1(0);struct epoll_event event = {.events = EPOLLIN | EPOLLET, .data.fd = server_fd};epoll_ctl(epoll_fd, EPOLL_CTL_ADD, server_fd, &event);set_nonblocking(server_fd);struct epoll_event events[MAX_EVENTS];while (1) {int n = epoll_wait(epoll_fd, events, MAX_EVENTS, -1);for (int i = 0; i < n; i++) {if (events[i].data.fd == server_fd) {  // 新連接struct sockaddr_in client_addr;socklen_t addr_len = sizeof(client_addr);int client_fd = accept(server_fd, (struct sockaddr*)&client_addr, &addr_len);if (client_fd < 0) continue;set_nonblocking(client_fd);epoll_ctl(epoll_fd, EPOLL_CTL_ADD, client_fd, &event);} else {  // 處理請求handle_request(events[i].data.fd);epoll_ctl(epoll_fd, EPOLL_CTL_DEL, events[i].data.fd, NULL);}}}close(server_fd);return 0;
}
  • 核心邏輯
    • GET 請求:訪問根路徑?/?時返回?xunfei.html?頁面
    • POST 請求:處理?/commit?路徑的表單提交,打印數據并返回成功提示

三、操作步驟(Ubuntu 虛擬機中執行)

1. 創建項目目錄

mkdir ~/Linux-HTTP && cd ~/Linux-HTTP  # 創建并進入項目目錄

?2. 編寫并保存文件

  • 使用?nano?或?vim?分別創建?xunfei.html?和?server.c,粘貼上述代碼并保存。

3. 編譯服務器

gcc server.c -o server  # 生成可執行文件

可能問題:若提示?gcc: command not found,需先安裝 GCC:

sudo apt update && sudo apt install gcc -y  # (首次編譯需執行,后續可忽略)

4. 運行服務器

./server  # 啟動服務器

輸出提示

服務器啟動,監聽端口 8080...

5. 訪問測試(兩種方式)

方式 1:虛擬機內直接訪問

打開終端,使用?curl?測試:

curl http://localhost:8080  # 查看 HTML 頁面內容
方式 2:宿主機通過瀏覽器訪問
  • 前提:確保虛擬機網絡設置為?橋接模式?或?NAT 模式,并開放端口。
  • 在宿主機瀏覽器輸入:
http://虛擬機IP:8080  # 例如:http://192.168.1.100:8080

?輸入表單數據并點擊 “提交”,觀察虛擬機終端輸出:

接收到表單數據:name=張三&age=20  # 示例輸出

?

四、常見問題與解決

1. 服務器啟動失敗(端口被占用)

lsof -i :8080  # 查看占用端口的進程
kill -9 <PID>   # 強制終止進程(PID 替換為實際進程號)

2. 無法訪問頁面(防火墻限制)

sudo ufw allow 8080/tcp  # 開放 8080 端口(Ubuntu 防火墻默認關閉,若啟用需執行)

?

3. 表單提交后數據亂碼

  • 確保 HTML 頭部包含?<meta charset="utf-8">
  • 服務器處理 POST 數據時,需根據編碼格式解析(示例代碼直接打印原始數據,如需處理可添加 URL 解碼邏輯)

五、擴展方向

  1. 優化請求處理
    • 支持更多 HTTP 方法(如 PUT、DELETE)
    • 添加靜態文件緩存機制
  2. 數據持久化
    • 將表單數據存入文件或數據庫(如 SQLite)
  3. 并發優化
    • 使用線程池替代 epoll 單線程模型
    • 實現長連接(Connection: keep-alive)

通過這個實例,你可以深入理解 HTTP 協議的基本交互流程,并為后續開發更復雜的 Web 服務奠定基礎。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/906630.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/906630.shtml
英文地址,請注明出處:http://en.pswp.cn/news/906630.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

LVS 負載均衡集群應用實戰

前提:三臺虛擬機,有nginx,要做負載 1. LVS-server 安裝lvs管理軟件 [root@lvs-server ~]# yum -y install ipvsadm 程序包:ipvsadm(LVS管理工具) 主程序:/usr/sbin/ipvsadm 規則保存工具:/usr/sbin/ipvsadm-save > /path/to/file 配置文件:/etc/sysconfig/ipvsad…

鴻蒙進階——Framework之Want 隱式匹配機制概述

文章大綱 引言一、Want概述二、Want的類型1、顯式Want2、隱式Want3、隱式Want的匹配 三、隱式啟動Want 源碼概述1、有且僅有一個Ability匹配2、有多個Ability 匹配需要彈出選擇對話框3、ImplicitStartProcessor::ImplicitStartAbility3.1、GenerateAbilityRequestByAction3.1.1…

Rules and Monetization

The system creates rules that allow them to monetize. The system doesn’t just enforce rules — it creates them strategically to monetize control. &#x1f527; How It Works: Invent a rule (e.g., “You need a permit to sell food.”)Claim it’s for safety …

java中string類型的list集合放到redis的5種數據類型的那種比較合適呢,可以用StringRedisTemplate實現

在Java中&#xff0c;如何將一個String類型的List集合存儲到Redis中&#xff0c;并且應該選擇Redis的哪種數據類型。同時&#xff0c;用戶還問到是否可以使用StringRedisTemplate來實現。 首先&#xff0c;我需要回憶一下Redis的5種主要數據類型&#xff1a;字符串&#xff08;…

基于DQN的學習資源難度匹配智能體

基于DQN的學習資源難度匹配智能體 下面我將實現一個基于DQN(深度Q網絡)的智能體,用于根據用戶的學習表現動態匹配適合難度的學習資源。這個系統可以應用于在線教育平臺,根據用戶的歷史表現自動調整推薦資源的難度級別。 1. 環境設置 首先我們需要定義學習環境,這里我創建…

OrangePi Zero2開發指南:從SDK獲取到交叉編譯全流程詳解

一、OrangePi Zero2 SDK說明 SDK 全稱 Software Development Kit&#xff0c;即軟件開發工具包。一般包括了一些工具&#xff08;如交叉編譯工具鏈&#xff09;、庫、文檔和示例代碼。香橙派的Linux SDK其實指的就是 orangepi-build 這套代碼集&#xff0c;orangepibuild 在腳…

MATLAB NLP 工具箱 文本預處理教程

文章目錄 前言一、文本預處理核心步驟二、MATLAB 實現示例三、高級預處理技術四、預處理流程整合五、性能優化與注意事項六、實戰案例&#xff1a;IMDB 影評預處理 前言 以下是 MATLAB 自然語言處理 (NLP) 工具箱的文本預處理教程&#xff0c;涵蓋核心步驟、代碼實現及最佳實踐…

大模型的量化與雙重量化(1)

文章目錄 大模型量化的含義和作用什么是量化量化的作用具體示例 雙重量化的含義和作用什么是雙重量化雙重量化的具體實現雙重量化的作用具體示例對比實際應用場景 大模型量化的含義和作用 什么是量化 量化是指將神經網絡中的參數&#xff08;權重和激活值&#xff09;從高精度…

ES6 新增 API 方法

ES6 新增 API 方法 目錄 ES6 新增 API 方法背景介紹數組方法1. Array.from()2. Array.of()3. find/findIndex4. includes5. flat/flatMap 對象方法1. Object.assign()2. Object.keys/values/entries3. Object.getOwnPropertyDescriptors() 字符串方法1. includes/startsWith/en…

vscode使用ssh鏈接服務器

vscode SSH vscode先下載remote ssh的插件&#xff0c;隨后在左邊的菜單欄里選擇遠程。 點擊新建連接&#xff0c;輸入用戶名和地址&#xff0c;-p參數指定端口 ssh ubuntu{ip} -p xxx 隨后就可以正常連接了&#xff0c;這里使用普通用戶的用戶名密碼&#xff0c;別用root。 配…

基于FPGA的電子萬年歷系統開發,包含各模塊testbench

目錄 1.課題概述 2.系統仿真結果 3.核心程序與模型 4.系統原理簡介 5.完整工程文件 1.課題概述 基于FPGA的電子萬年歷系統開發,包含各模塊testbench。主要包含以下核心模塊&#xff1a; 時鐘控制模塊&#xff1a;提供系統基準時鐘和計時功能。 日歷計算模塊&#xff1a…

C++ 的 out_ptr 和 inout_ptr

1 問題的起因 1.1 T** 或 T&* ? C 的智能指針可以通過 get() 和 * 的重載得到原始指針 T*&#xff0c;遇到這樣的 C 風格的函數的時候&#xff1a; void Process(Foo *ptr);std::unique_ptr<Foo> sp ...;Process(sp.get()); //調用 Process 函數Process() 函數以…

取消 Conda 默認進入 Base 環境

在安裝 Conda 后&#xff0c;每次打開終端時默認會進入 base 環境。可以通過以下方法取消這一默認設置。 方法一&#xff1a;使用命令行修改配置 在終端中輸入以下命令&#xff0c;將 auto_activate_base 參數設置為 false&#xff1a; conda config --set auto_activate_ba…

數字計數--數位dp

1.不考慮前導零 2.每一位計數&#xff0c;就是有點“數頁碼”的意思 P2602 [ZJOI2010] 數字計數 - 洛谷 相關題目&#xff1a;記得加上前導零 數頁碼--數位dp-CSDN博客 https://blog.csdn.net/2301_80422662/article/details/148160086?spm1011.2124.3001.6209 #include…

Redis學習打卡-Day5-Redis 持久化

單點 Redis 的一些問題 數據丟失&#xff1a;Redis 是內存存儲&#xff0c;服務重啟可能會丟失數據。solution&#xff1a;實現 Redis 數據持久化。并發能力&#xff1a;單節點 Redis 并發能力雖然不錯&#xff0c;但也無法滿足如618這樣的高并發場景。solution&#xff1a;搭…

飛書知識問答深度體驗:企業AI應用落地的典范產品

飛書知識問答深度體驗&#xff1a;企業AI應用落地的典范產品 產品介紹-飛書知識問答是什么與常規通用大模型相比有何優點&#xff1f;大模型橫行的時代&#xff0c;飛書知識問答對普通人和企業有何影響呢&#xff1f; 場景示例-不同角色可以用飛書知識問答做什么&#xff1f;對…

Python打卡訓練營學習記錄Day34

知識點回歸&#xff1a; CPU性能的查看&#xff1a;看架構代際、核心數、線程數 GPU性能的查看&#xff1a;看顯存、看級別、看架構代際 GPU訓練的方法&#xff1a;數據和模型移動到GPU device上 類的call方法&#xff1a;為什么定義前向傳播時可以直接寫作self.fc1(x) CPU性…

Django的請求和響應+template模板

&#x1f31f; 如果這篇文章觸動了你的心弦&#xff0c;請不要吝嗇你的支持&#xff01; 親愛的讀者&#xff0c; 感謝你花時間閱讀這篇分享。希望這里的每一個字都能為你帶來啟發或是讓你會心一笑。如果你覺得這篇文章有價值&#xff0c;或者它解決了你一直以來的一個疑問&a…

Python |GIF 解析與構建(2):狀態機解析

Python &#xff5c;GIF 解析與構建&#xff08;2&#xff09;&#xff1a;狀態機解析 目錄 Python &#xff5c;GIF 解析與構建&#xff08;2&#xff09;&#xff1a;狀態機解析 引言 一、狀態機概述 狀態機的優勢與改進方向 總結 引言 在《Python &#xff5c;GIF 解…

PCB設計實踐(二十六)貼片電容與插件電容的全面解析:差異、演進與應用場景

一、核心差異&#xff1a;結構與性能對比 物理結構與封裝形式 貼片電容&#xff08;Surface Mount Device, SMD&#xff09;采用扁平化設計&#xff0c;外形多為長方體或圓柱體&#xff0c;直接通過焊盤固定在電路板表面。其封裝材料通常為陶瓷、聚合物或鋁電解層&#xff0c;外…