深入探討 UDP 協議與多線程 HTTP 服務器

深入探討 UDP 協議與多線程 HTTP 服務器

一、UDP 協議:高效但“不羈”的傳輸使者

UDP 協議以其獨特的特性在網絡傳輸中占據一席之地,適用于對實時性要求高、能容忍少量數據丟失的場景。
請添加圖片描述

1. UDP 的特點解析

  • 無連接:無需提前建立連接,如同“不打電話直接寄快遞”,減少了連接建立的時間開銷,想發就發。
  • 不可靠:不保證數據一定到達、不檢測錯誤、不排序。但這也讓它省去了復雜的確認機制,適合視頻通話、在線游戲等場景,偶爾卡頓或丟包可接受。
  • 數據報傳輸:以“塊”為單位傳輸(數據報),發送端發多少,接收端收多少,保持原始邊界。例如發送“abc”和“def”,接收端不會合并為“abcdef”。
  • 速度快、開銷小:頭部僅 8 字節(TCP 為 20 字節),額外負擔少,傳輸效率高,適合直播、DNS 查詢等“搶時間”場景。
  • 不適應網絡擁塞控制:無“減速”機制,網絡擁堵時可能丟包更多,但能保持快速發送,與 TCP 的自適應減速形成對比。
  • 支持多種通信方式:可單播(一對一)、廣播/組播(一對多),如網課直播向多個設備同時發送數據。

一句話總結:UDP 如同“快遞急件”,速度快但不確保簽收,適合實時性要求高或簡單傳輸的場景。

2. UDP 網絡編程代碼解析

服務器端(ser.c
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  int main() {  // 創建 UDP 套接字,AF_INET 表示 IPv4,SOCK_DGRAM 表示 UDP 類型,0 表示默認協議  int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  if (sockfd == -1) {  perror("socket err");  exit(1);  }  struct sockaddr_in saddr, caddr;  memset(&saddr, 0, sizeof(saddr));  saddr.sin_family = AF_INET;  saddr.sin_port = htons(6000); // 端口號轉網絡字節序  saddr.sin_addr.s_addr = inet_addr("127.0.0.1"); // 綁定本地回環地址  // 綁定套接字到指定地址和端口  int res = bind(sockfd, (struct sockaddr*)&saddr, sizeof(saddr));  if (res == -1) {  perror("bind err\n");  exit(1);  }  while (1) {  char buff[128] = {0};  int len = sizeof(caddr);  // 接收數據,recvfrom 用于 UDP,可獲取發送方地址  int n = recvfrom(sockfd, buff, 128, 0, (struct sockaddr*)&caddr, &len);  printf("recvfrom(%s) buff:%s\n", inet_ntoa(caddr.sin_addr), buff);  // 向發送方回復“ok”  sendto(sockfd, "ok", 2, 0, (struct sockaddr*)&caddr, sizeof(caddr));  }  close(sockfd);  
}  
客戶端(cli.c
#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  int main() {  int sockfd = socket(AF_INET, SOCK_DGRAM, 0);  if (sockfd == -1) {  perror("socket err");  exit(1);  }  struct sockaddr_in saddr;  saddr.sin_family = AF_INET;  saddr.sin_port = htons(6000);  saddr.sin_addr.s_addr = inet_addr("127.0.0.1");  while (1) {  printf("input:\n");  char buff[128] = {0};  fgets(buff, 128, stdin);  if (strncmp(buff, "end", 3) == 0) {  break;  }  // 向服務器發送數據  sendto(sockfd, buff, strlen(buff) - 1, 0, (struct sockaddr*)&saddr, sizeof(saddr));  memset(buff, 0, 128);  int len = sizeof(saddr);  // 接收服務器響應  recvfrom(sockfd, buff, 128, 0, (struct sockaddr*)&saddr, &len);  printf("buff(%s):%s\n", inet_ntoa(saddr.sin_addr), buff);  }  close(sockfd);  
}  
  • 服務器端:創建 UDP 套接字,綁定到 127.0.0.1:6000,循環接收客戶端數據,打印發送方 IP 和數據,回復“ok”。
  • 客戶端:創建 UDP 套接字,循環讀取用戶輸入,發送給服務器,接收并打印服務器響應,輸入“end”時退出。

二、多線程 HTTP 服務器:構建 Web 通信樞紐

HTTP 協議(端口 80,HTTPS 為 443)是應用層的核心協議,基于 TCP 協議,具有無狀態、簡單靈活等特點,廣泛用于 Web 通信。多線程設計使其能并發處理多個客戶端請求,提升性能。
請添加圖片描述

1. HTTP 協議深度解析

  • 請求方法:常見的有 GET(獲取資源)、POST(提交數據)、PUT(更新資源)、DELETE(刪除資源)等。例如,瀏覽器訪問網頁使用 GET 請求獲取頁面內容。
    在這里插入圖片描述

  • 狀態碼

    • 2xx(如 200 OK):表示請求成功。
    • 4xx(如 404 NOT FOUND):客戶端錯誤,資源不存在。
    • 5xx(如 500 Internal Server Error):服務器內部錯誤。
      在這里插入圖片描述
  • 長連接與短連接

    • 短連接:每次請求都新建 TCP 連接,完成后關閉。適用于請求不頻繁的場景,如普通網頁瀏覽。
    • 長連接(Keep-Alive):多個請求復用一個 TCP 連接,減少連接建立開銷,提升效率,適用于頻繁交互的場景,如單頁應用(SPA)。
  • 無狀態特性:HTTP 協議本身不記錄客戶端狀態,通過 CookieSession 等機制實現會話跟蹤。例如,用戶登錄后,服務器通過 Cookie 識別用戶后續請求。

  • http請求報文如下圖
    在這里插入圖片描述

  • http應答報文如下圖
    在這里插入圖片描述

2. 多線程 HTTP 服務器代碼詳解

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>  
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>  
#include <pthread.h>  
#include <fcntl.h>  #define PATH "/home/stu/0101/http"  
int socket_init();  
char *strtok_fun(char buff[]) {  char *saveptr;  // 解析請求頭第一行,獲取請求的文件名。例如,對于“GET /index.html HTTP/1.1”,提取“/index.html”  char *p = strtok_r(buff, " ", &saveptr);  if (p != NULL) {  p = strtok_r(NULL, " ", &saveptr);  return p;  }  return NULL;  
}  void *thread_fun(void *arg) {  int c = *((int *)arg);  free(arg);  while (1) {  char buff[1024] = {0};  int n = recv(c, buff, 1024, 0);  if (n == 0) { // 客戶端關閉連接,recv 返回 0  break;  }  if (n == -1) {  perror("recv err");  break;  }  char *filename = strtok_fun(buff);  if (filename == NULL) {  break;  }  if (strcmp(filename, "/") == 0) {  filename = "/index.html"; // 若請求根路徑,默認返回 index.html  }  char path[256];  strcpy(path, PATH);  strcat(path, filename);  printf("path:%s\n", path);  int file_id = open(path, O_RDONLY);  if (file_id == -1) { // 文件不存在,構造 404 響應頭  char head[256] = {"HTTP/1.1 404 NOT FOUND\r\n"};  strcat(head, "Server: myhttp\r\n");  sprintf(head + strlen(head), "Content-Length: 0\r\n");  strcat(head, "\r\n");  send(c, head, strlen(head), 0);  break;  }  int filesize = lseek(file_id, 0, SEEK_END);  lseek(file_id, 0, SEEK_SET);  char head[256] = {"HTTP/1.1 200 OK\r\n"};  strcat(head, "Server: myhttp\r\n");  sprintf(head + strlen(head), "Content-Length: %d\r\n", filesize);  strcat(head, "\r\n");  send(c, head, strlen(head), 0); // 發送 200 響應頭,包含服務器信息、內容長度等  char data[1024] = {0};  int num = 0;  while ((num = read(file_id, data, 1024)) > 0) {  send(c, data, num, 0); // 分塊讀取文件內容并發送給客戶端  }  close(file_id);  }  printf("cli close");  close(c);  pthread_exit(NULL);  
}  int main() {  int sockfd = socket_init();  if (sockfd == -1) {  exit(1);  }  while (1) {  int c = accept(sockfd, NULL, NULL);  if (c == -1) {  perror("accept err");  continue;  }  pthread_t id;  int *p = (int *)malloc(sizeof(int));  *p = c;  if (pthread_create(&id, NULL, thread_fun, (void *)p) != 0) {  perror("pthread_create err");  free(p);  close(c);  } else {  pthread_detach(id); // 分離線程,使其結束后自動釋放資源,避免內存泄漏  }  }  
}  int socket_init() {  int sockfd = socket(AF_INET, SOCK_STREAM, 0); // 創建 TCP 套接字,SOCK_STREAM 表示面向連接的 TCP  if (sockfd == -1) {  perror("socket err");  return -1;  }  struct sockaddr_in saddr;  saddr.sin_family = AF_INET;  saddr.sin_port = htons(80); // 綁定 80 端口,HTTP 協議默認端口  saddr.sin_addr.s_addr = inet_addr("127.0.0.1");  int res = bind(sockfd, (struct sockaddr *)&saddr, sizeof(saddr));  if (res == -1) {  perror("bind err");  return -1;  }  if (listen(sockfd, 5) == -1) {  perror("listen err");  return -1;  }  return sockfd;  
}  
  • socket_init 函數:初始化 TCP 套接字,綁定到 127.0.0.1:80,通過 listen 開始監聽,使服務器處于等待客戶端連接狀態。
  • main 函數:循環調用 accept 接收客戶端連接。每收到一個連接,創建新線程處理(thread_fun),通過 pthread_detach 分離線程,確保線程結束后資源自動釋放,避免服務器資源泄漏。
  • thread_fun 函數
    • 讀取客戶端請求數據,解析請求頭獲取文件名。
    • 根據文件名構造文件路徑,嘗試打開文件。若文件不存在,發送 404 響應頭;若存在,發送 200 響應頭(包含 HTTP 協議版本、狀態碼、服務器名稱、內容長度等),然后分塊讀取文件內容并發送給客戶端。
    • 處理完一個客戶端請求后,關閉連接套接字,線程退出。

3. 多線程 HTTP 服務器的優勢

  • 并發處理:每個客戶端連接獨立分配線程,多個客戶端請求可同時處理,提升服務器吞吐量,避免單個請求阻塞影響整體服務。
  • 資源利用:充分利用多核 CPU 資源,線程間相互獨立,提高系統資源利用率。
  • 響應速度:及時處理客戶端請求,減少等待時間,提升用戶體驗,尤其適合高并發場景,如電商網站、新聞門戶等。

UDP 協議以其高效簡潔適用于特定場景,而多線程 HTTP 服務器通過并發處理與 HTTP 協議特性結合,成為 Web 通信的重要支柱。深入理解這些技術,能更好地應對網絡編程挑戰,構建強大穩定的網絡應用。

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

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

相關文章

引用第三方自定義組件——微信小程序學習筆記

1. 使用 npm 安裝第三方包 1.1 下載安裝Node.js 工具 下載地址&#xff1a;Node.js — Download Node.js 1.2 安裝 npm 包 在項目空白處右鍵彈出菜單&#xff0c;選擇“在外部終端窗口打開”&#xff0c;打開命令行工具&#xff0c;輸入以下指令&#xff1a; 1> 初始化:…

數字化轉型是往哪轉?怎么轉?

寫在前面 當下數字化轉型的風還在吹&#xff0c;企業數字化轉型過程中以數字化項目滿足業務化需求&#xff0c;已有相關數字化平臺的話&#xff0c;就搞大平臺、大系統&#xff0c;解決數據孤島。政府數字化轉型亦是如此&#xff0c;某些省市發了系統優化整合的文&#xff0c;旨…

嵌入式學習--江協51單片機day2

今天學的不多&#xff0c;內容為&#xff1a;靜態、動態數碼管的控制&#xff0c;模塊化編程和lcd1602調試工具 數碼管的控制 由于內部電路的設計&#xff0c;數碼管每次只能顯示一個位置的一個數字&#xff0c;動態的實現是基于不同位置的閃爍頻率高。 P2_4,P2_3,P2_2控制位…

《數據結構:二叉搜索樹(Binary Search Tree)》

文章目錄 :red_circle:一、二叉搜索樹的概念:red_circle:二、二叉搜索樹的性能分析:red_circle:三、二叉搜索樹的操作&#xff08;一&#xff09;插入&#xff08;二&#xff09;查找&#xff08;三&#xff09;刪除 :red_circle:四、二叉搜索樹的實現代碼&#xff08;一&#…

【Linux相關】實時查看Nvidia-smi使用情況

【Linux相關】 實時查看Nvidia-smi使用情況 文章目錄 實時查看Nvidia-smi使用情況 實時查看Nvidia-smi使用情況 在本地終端執行下述語句 watch -n 1 nvidia-smi每一秒都會更新&#xff0c;將 1 改為其他數字可以滿足不同需求

Kotlin密封類優化Android狀態管理

Kotlin 的密封類&#xff08;Sealed Class&#xff09;確實是 Android 開發中管理復雜 UI 狀態的利器。它通過類型安全的層次結構&#xff0c;讓狀態管理代碼更加清晰簡潔。讓我們從實際開發場景出發&#xff0c;深入探討其應用&#xff1a; 一、密封類核心優勢 受限的類繼承…

JavaWeb:SpringBootWeb快速入門

介紹 Spring SpringBoot 入門程序 需求 步驟 修改端口 1.新建application.yml #設置端口 server:port: 8081入門程序-分析 為什么main方法能啟動web應用-內嵌tomcat 為什么tomcat能定位HelloController程序 請求先到DisPatcherServlet&#xff0c;根據路徑轉發 小結 1.…

Unity學習筆記二

文章目錄 3D數學公共計算結構體Mathf常用成員三角函數 向量Vector3基本成員點乘叉乘插值運算 四元數引出基本概念Quaternion結構體成員四元數運算 更多的Mono延遲函數協同程序多線程相關協程概念辨析協程本體協程調度器 Resources資源動態加載特殊文件夾Resources同步加載Resou…

為什么Transformer推理需要做KV緩存

一、我們先來回憶一下在transformer中KV在哪里出現過&#xff0c;都有什么作用&#xff1f; α的計算過程&#xff1a; 這里引入三個向量&#xff1a; 圖中的q為Query&#xff0c;用來匹配key值 圖中的k為key,用來被Query匹配 圖中的Value&#xff0c;是用來被進行加權平均的 由…

【大模型面試】大模型(LLMs)高頻面題全面整理(★2025年5月最新版★)

【大模型面試】大模型&#xff08;LLMs&#xff09;高頻面題全面整理&#xff08;★2025年5月最新版★&#xff09; &#x1f31f; 嗨&#xff0c;你好&#xff0c;我是 青松 &#xff01; &#x1f308; 自小刺頭深草里&#xff0c;而今漸覺出蓬蒿。 本筆記適合大模型初學者和…

JAVA:使用 iTextPDF 處理 PDF 的技術詳解

1、簡述 iTextPDF 是一個功能強大的 Java PDF 庫,可以用來創建、修改和處理 PDF 文檔。通過它,我們可以完成如生成 PDF、讀取 PDF 內容、添加水印、合并 PDF 等多種操作。本篇博客將詳細介紹 iTextPDF 的使用方法,并提供一些實踐樣例,幫助開發者快速上手。 樣例代碼: htt…

模態與非模態窗口及使用時的數據交互

模態窗口使用exec()方法顯示&#xff0c;會阻塞父窗口&#xff0c;直到對話框關閉&#xff1b; 非模態對話框允許同時操作主窗口和設置窗口&#xff0c;使用show()。 模態和非模態的主要區別在于用戶能否與父窗口交互&#xff0c;非模態更適合需要頻繁切換的場景。非模態窗口需…

Docker進入MySQL之后如何用sql文件初始化數據

關閉Docker-compose.yml里面所有容器 docker compose -f docker_compose.yml down后臺形式開啟Docker-compose.yml所有容器 docker compose -f docker_compose.yml up -d羅列出所有啟動過的&#xff08;包括退出過的&#xff09;容器 docker ps -a進入指定容器ID內部 docke…

MAC 地址

MAC地址&#xff08;Media Access Control Address&#xff09;是指網絡設備在數據鏈路層使用的唯一標識符&#xff0c;也稱為硬件地址或物理地址。它用于標識設備之間的網絡通信&#xff0c;是網絡適配器&#xff08;如網卡、Wi-Fi適配器等&#xff09;的唯一標識。每個網絡設…

Redis 7.0中5種新特性及實戰應用

Redis 7.0引入了多項革命性的新特性&#xff0c;不僅在性能和可靠性方面有所提升&#xff0c;更在功能和使用體驗上有了質的飛躍。本文將介紹Redis 7.0的五大關鍵新特性&#xff0c;可以根據實際情況利用Redis 7.0的強大功能&#xff0c;構建更高效、更可靠的應用系統。 特性一…

PHP實現PDF自動簽名

技術要點&#xff1a;在PDF中找到一個固定錨點&#xff0c;在需要放置圖片的地方找到測試出錨點對應的XY位 // 使用了poppler方法&#xff0c;其他PDF庫在獲取坐標方面有各種問題&#xff0c;他的安裝是在Linux底層&#xff0c;比在PHP項目中用Composer安裝的庫看上去更穩定&a…

中達瑞和便攜式高光譜相機:珠寶鑒定領域的“光譜之眼”

在珠寶行業中&#xff0c;真偽鑒定始終是核心需求。隨著合成技術與優化處理手段的日益精進&#xff0c;傳統鑒定方法逐漸面臨挑戰。中達瑞和推出的便攜式高光譜相機&#xff0c;憑借其獨特的“圖譜合一”技術&#xff0c;為珠寶真假鑒定提供了科學、高效且無損的解決方案&#…

2025年滲透測試面試題總結-某戰隊紅隊實習面經(附回答)(題目+回答)

網絡安全領域各種資源&#xff0c;學習文檔&#xff0c;以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各種好玩的項目及好用的工具&#xff0c;歡迎關注。 目錄 某戰隊紅隊實習面經 個人經歷與技術能力 2. HVV/攻防演練成績 3. 上一個工作主要內容 4. 有意思的邏…

【PostgreSQL數據分析實戰:從數據清洗到可視化全流程】5.1 描述性統計分析(均值/方差/分位數計算)

&#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 &#x1f449; 點擊關注不迷路 文章大綱 5.1 描述性統計分析&#xff1a;均值、方差與分位數計算實戰5.1.1 數據準備與分析目標數據集介紹分析目標 5.1.2 均值計算&#xff1a;從整體到分組分析總體均值計算加權均值…

npm下載插件無法更新package.json和package-lock.json文件的解決辦法

經過多番查證&#xff0c;使用npm config ls查看相關配置等方式&#xff0c;最后發現全局的.npmrc文件的配置多寫了globaltrue&#xff0c;去掉就好了 如果參數很多&#xff0c;不知道是哪個參數引起的&#xff0c;先只保留registryhttp://xxx/&#xff0c;試試下載&#xff0…