TCP三次握手、四次揮手+多線程并發處理

目錄

一、三次握手建立連接

1.1 標記位

1.2 三次握手的過程

二、四次揮手斷開連接

?三、模擬服務器和客戶端收發數據

四、多線程并發處理

五、TCP粘包問題

5.1 什么是TCP粘包?

5.2 TCP粘包會有什么問題?

5.3 TCP粘包的解決方法?


一、三次握手建立連接

1.1 標記位

????????SYN:用于建立連接的初始握手。發送方發送一個SYN報文段給接收方,請求建立連接。

????????ACK:用于確認數據的傳輸。當成功接收到數據后,接收方發送一個帶有ACK標記的報文段回復發送方,確認已經收到了數據。

????????FIN:用于關閉連接。當發送方發送完所有數據后,會發送一個帶有FIN標記的報文段,請求關閉連接。接收方在收到FIN報文段后,發送一個帶有ACK標記的報文段進行確認,并使用一個定時器在一段時間后關閉連接。

1.2 三次握手的過程

三次握手是TCP協議中用于建立連接的過程,具體步驟如下:

  1. 客戶端向服務器發送一個SYN(同步)的數據包,表示客戶端請求建立連接。該數據包中還包含客戶端隨機生成的初始序列號(Sequence Number,seq),比如 seq = x。
  2. 服務器收到客戶端發送的SYN數據包后,向客戶端發送一個ACK(確認)和SYN的組合數據包,服務器將自己的初始序列號(seq = y)發送給客戶端,同時將客戶端的序列號加 1 作為確認號(Acknowledgment Number,ack = x + 1),表示服務器同意建立連接,并向客戶端發送確認信息。
  3. 客戶端收到服務器發送的ACK和SYN的數據包后,向服務器發送一個ACK確認數據包,該包的確認號為服務器的序列號加 1(ack = y + 1),而序列號為客戶端在第一次握手中發送的序列號加 1(seq = x + 1),表示客戶端也同意建立連接。

經過以上三個步驟,客戶端和服務器就成功建立了連接,可以開始進行數據傳輸。這個過程就是TCP協議中三次握手的過程。

圖解如下:

二、四次揮手斷開連接

四次揮手是TCP協議中用于關閉連接的過程,具體步驟如下:

  1. 第一次揮手:當客戶端確定自己已經沒有數據要發送時,向服務器發送一個FIN(結束)數據包,其中包含自己的序列號(seq = u),表示客戶端關閉數據傳輸。
  2. 第二次揮手:服務器接收到客戶端發送的FIN后,向客戶端發送一個ACK確認數據包,確認號為客戶端的序列號加 1(ack = u + 1),表示服務器收到了關閉請求。此時,服務器可能還有數據需要繼續發送,所以連接不會立即關閉,而是進入半關閉狀態。
  3. 第三次揮手:當服務器確定自己沒有數據要發送時,向客戶端發送一個FIN數據包,其中包含自己的序列號(seq = v),表示服務器也準備關閉連接。
  4. 第四次揮手:客戶端接收到服務器發送的FIN后,向服務器發送一個ACK確認數據包,確認號為服務器的序列號加 1(ack = v + 1),序列號為之前發送 FIN 包時的序列號加 1(seq = u + 1),表示客戶端收到了關閉請求,連接正式關閉。

通過以上四個步驟,客戶端和服務器完成了關閉連接的過程。值得注意的是,四次揮手中的每一次揮手都需要對方發送確認,確保雙方都能安全地關閉連接。

圖解如下:

那么,揮手能不能是3次呢?答案是可以的,第二次揮手和第三次揮手是可以合并在一起的。

?三、模擬服務器和客戶端收發數據

服務器ser

#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 socket_init();int main()
{int sockfd=socket_init();if(sockfd==-1){exit(1);}while(1){struct sockaddr_in caddr;//記錄客戶端地址ip,portint len=sizeof(caddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//caddr存放客戶端ip,port,可能會阻塞if(c<0){continue;}printf("accept c=%d\n",c);while(1){char buff[128]={0};int n=recv(c,buff,127,0);//有可能阻塞,如果返回-1則失敗,是0則對方關閉了if(n<=0){break;}printf("recv:%s\n",buff);send(c,"ok",2,0);//write(c,"ok",2);}close(c);printf("cilent close\n");}
}
int socket_init()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//TCP,創建套接字if(sockfd==-1){return -1;}struct sockaddr_in saddr;//ipv4地址族,對應套接字的地址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));//綁定ip,port,指定if(res==-1){printf("bind err\n");return -1;}res=listen(sockfd,5);//創建監聽隊列if(res==-1){return -1;}return sockfd;
}
  1. 先調用socket_init()函數初始化服務器端的套接字,綁定IP和端口,并開始監聽連接請求。
  2. 不斷循環accept()函數接受客戶端的連接請求,一旦有客戶端連接則創建一個新的套接字來處理與客戶端的通信。
  3. 在客戶端連接成功后,進入一個無限循環,不斷接收客戶端發送的消息,并打印消息內容。
  4. 如果接收到的消息長度小于等于0,則說明客戶端關閉了連接,跳出循環,關閉與客戶端的連接。
  5. 如果收到消息,則回復客戶端消息為"ok", 繼續接受下一條消息。

客戶端cil

#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_STREAM,0);if(sockfd==-1){exit(1);}struct sockaddr_in saddr;//服務器的地址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=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//發起連接,三次握手if(res==-1){printf("connet err\n");exit(1);}while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff=%s\n",buff);}close(sockfd);exit(0);
}
  1. 創建了一個套接字socket,并指定為AF_INET和SOCK_STREAM,表示使用IPv4和TCP協議。
  2. 初始化服務器的地址saddr,包括IP地址為"127.0.0.1"、端口號為6000等信息。
  3. 調用connect()函數連接到服務器端,進行三次握手建立連接。
  4. 進入一個循環,不斷接收用戶輸入的消息,將消息發送給服務器,并接收服務器的回復。
  5. 如果用戶輸入為"end",則跳出循環,關閉套接字,結束程序。

運行結果:

那么send后會直接將數據發送出去嗎?答案不然,會將數據先發送到發送緩沖區,然后將數據發給接收緩沖區,最后才會接收到數據。

我們來驗證一下:

?把ser.c中的int n = recv(c,buff,127,0)改為int n = recv(c,buff,1,0),執行后結果:

每輸一個應該輸出五個ok,但此時只輸出一個ok,剩下四個ok在recv的緩沖區中,4個ok八個字符所以緩沖區有8個字符。

通過netstat -natp 命令可以顯示

再輸入一個a,輸出四個ok

此時緩沖區中有一個ok,2個字符

TCP字節流服務

四、多線程并發處理

服務器ser

#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>int socket_init();
void* fun(void* arg)
{int* p=(int*)arg;int c=*p;free(p);while(1){char buff[128]={0};int n=recv(c,buff,127,0);//有可能阻塞,如果返回-1則失敗,是0則對方關閉了if(n<=0){break;}printf("recv:%s\n",buff);send(c,"ok",2,0);//write(c,"ok",2);}close(c);printf("cilent close\n");
}
int main()
{int sockfd=socket_init();if(sockfd==-1){exit(1);}while(1){struct sockaddr_in caddr;//記錄客戶端地址ip,portint len=sizeof(caddr);int c=accept(sockfd,(struct sockaddr*)&caddr,&len);//caddr存放客戶端ip,port,可能會阻塞if(c<0){continue;}printf("accept c=%d\n",c);int* p=(int*)malloc(sizeof(int));if(p==NULL){close(c);continue;}*p=c;pthread_t id;pthread_create(&id,NULL,fun,(void*)p);}
}
int socket_init()
{int sockfd=socket(AF_INET,SOCK_STREAM,0);//TCP,創建套接字if(sockfd==-1){return -1;}struct sockaddr_in saddr;//ipv4地址族,對應套接字的地址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));//綁定ip,port,指定if(res==-1){printf("bind err\n");return -1;}res=listen(sockfd,5);//創建監聽隊列if(res==-1){return -1;}return sockfd;
}

客戶端cil

#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_STREAM,0);if(sockfd==-1){exit(1);}struct sockaddr_in saddr;//服務器的地址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=connect(sockfd,(struct sockaddr*)&saddr,sizeof(saddr));//發起連接,三次握手if(res==-1){printf("connet err\n");exit(1);}while(1){printf("input:\n");char buff[128]={0};fgets(buff,128,stdin);if(strncmp(buff,"end",3)==0){break;}send(sockfd,buff,strlen(buff)-1,0);memset(buff,0,128);recv(sockfd,buff,127,0);printf("buff=%s\n",buff);}close(sockfd);exit(0);
}

?運行結果:

五、TCP粘包問題

5.1 什么是TCP粘包?

????????TCP粘包是指發送方連續發送的多個數據包,在傳輸過程中可能會被TCP協議合并成一個大的數據包,在接收方收到時無法正確區分這些數據包的邊界,導致粘在一起,從而引起粘包現象。這樣就會影響接收方對數據的解析和處理簡而言之,就是多次send發送數據,被對方一次recv收到了。

5.2 TCP粘包會有什么問題?

  1. 數據解析錯誤:如果接收方無法正確區分數據包的邊界,可能導致數據解析錯誤,無法按照預期的方式處理數據。
  2. 數據錯誤:如果多個數據包粘在一起,可能導致數據包數據內容混雜,造成數據錯誤或丟失。
  3. 性能影響:數據粘包會增加解析數據的復雜性,影響系統性能。

5.3 TCP粘包的解決方法?

  1. 消息定長:在發送方和接收方約定固定的消息長度,每次發送和接收的數據長度相同,這樣接收方可以根據固定長度來截取數據包。
  2. 使用特殊符號分隔:在數據包之間加入特殊符號作為分隔符,接收方根據分隔符來區分不同數據包。
  3. 增加消息頭:在數據包頭部添加額外的消息頭信息,包括消息長度等,接收方通過消息頭信息來解析數據包。

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

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

相關文章

使用HunyuanVideo搭建文本生視頻大模型

1.摘要 HunyuanVideo是一個全新的開源視頻基礎模型&#xff0c;其視頻生成性能堪比領先的閉源模型&#xff0c;甚至超越它們。我們采用了多項模型學習的關鍵技術&#xff0c;通過有效的模型架構和數據集擴展策略&#xff0c;我們成功訓練了一個擁有超過 130 億個參數的視頻生成…

LabVIEW圓錐滾子視覺檢測系統

基于LabVIEW平臺的視覺檢測系統提高圓錐滾子內組件的生產質量和效率。通過集成高分辨率攝像頭和先進的圖像處理算法&#xff0c;系統能夠自動識別和分類產品缺陷&#xff0c;從而減少人工檢查需求&#xff0c;提高檢測的準確性和速度。 ?? ? 項目背景 隨著制造業對產品質…

mac 基于Docker安裝minio服務器

在 macOS 上基于 Docker 安裝 MinIO 是一個高效且靈活的方案&#xff0c;尤其適合本地開發或測試環境。以下是詳細的安裝與配置步驟&#xff0c;結合了最佳實踐和常見問題的解決方案&#xff1a; 一、安裝 Docker Desktop 下載安裝包 訪問 Docker 官網&#xff0c;下載適用于 …

EchoMimicV2 部署記錄

在這里插入代碼片# 虛擬環境配置 pip install pip -U pip install torch2.5.1 torchvision0.20.1 torchaudio2.5.1 xformers0.0.28.post3 --index-url https://download.pytorch.org/whl/cu124 pip install torchao --index-url https://download.pytorch.org/whl/nightly/cu1…

數據升降級:醫療數據的“時空穿梭“系統工程(分析與架構篇)

一、核心挑戰與量化分析 1. 版本演化困境的深度解析 (1) 格式斷層的結構化危機 數據轉換黑洞:某醫療信息平臺(2021-2023)統計顯示: 數據類型CDA R1→R2轉換失敗率R2→FHIR轉換失敗率關鍵失敗點診斷記錄28.4%19.7%ICD編碼版本沖突(18.7%)用藥記錄15.2%12.3%劑量單位標準化…

個人開發免費好用

聊一聊 現在輸入法非常多&#xff0c;有時候都不知道哪個更好用。 其實&#xff0c;只有多嘗試&#xff0c;才能找到適合自己的。 今天給大家分享一款輸入法&#xff0c;用起來比較順手&#xff0c;大家可以試試。 軟件介紹 BL輸入法 這是一款綠色純凈&#xff0c;安全放心…

Windows查看和修改IP,IP互相ping通

Windows系統 查看IP地址 winr 輸入cmd 打開終端使用 ipconfig 或 ipconfig -all 命令查看當前網絡 IPV4地址 Windows系統 修改IP地址 自動獲取IP&#xff08;DHCP&#xff09;&#xff1a; 打開 控制面板&#xff0c;點擊 網絡和Internet。點擊 網絡和共享中心。選擇 更改適配…

【IP101】圖像處理基礎:從零開始學習顏色操作(RGB、灰度化、二值化、HSV變換)

&#x1f3a8; 顏色操作詳解 &#x1f31f; 在圖像處理的世界里&#xff0c;顏色操作就像是一個魔術師的基本功。今天&#xff0c;讓我們一起來解鎖這些有趣又實用的"魔法"吧&#xff01; &#x1f4da; 目錄 通道替換 - RGB與BGR的"調包"游戲灰度化 - 讓…

windows系統搭建自己的ftp服務器,保姆級教程(用戶驗證+無驗證)

前言 最近在搭建環境時&#xff0c;我發現每次都需要在網上下載依賴包和軟件&#xff0c;這不僅耗時&#xff0c;而且有時還會遇到網絡不穩定的問題&#xff0c;導致下載速度慢或者中斷&#xff0c;實在不太方便。于是&#xff0c;我產生了搭建一個FTP服務器的想法。通過搭建FT…

藍橋杯 7. 晚會節目單

晚會節目單 原題目鏈接 題目描述 小明要組織一臺晚會&#xff0c;總共準備了 n 個節目。然而晚會時間有限&#xff0c;他只能從中選擇 m 個節目。 這 n 個節目是按照小明設想的順序給定的&#xff0c;順序不能改變。 小明發現觀眾對于晚會的喜歡程度與前幾個節目的好看程度…

JavaScript如何實現類型判斷?

判斷一個數據的類型&#xff0c;常用的方法有以下幾種&#xff1a; typeofinstanceofObject.prototype.toString.call(xxx) 下面來分別分析一下這三種方法各自的優缺點 typeof typeof的本意是用來判斷一個數據的數據類型&#xff0c;所以返回的也是一個數據類型。但是會遇到下…

哈希表筆記(四)Redis對比Java總結

文章目錄 一、基礎結構對比數據結構定義Java HashMapRedis字典 主要區別與設計思路 二、關鍵操作API對比初始化Java HashMapRedis字典 添加元素Java HashMapRedis字典 查找元素Java HashMapRedis字典 刪除元素Java HashMapRedis字典 擴容/重哈希操作Java HashMapRedis字典 三、…

docker拉取國內鏡像

1. 場景 最近整了一個tencent云服務器&#xff0c;想要玩一下docker&#xff0c;結果發現拉不下來&#xff0c;鏡像根本拉不下來。 2. 原因 1.云服務器無法訪問外網&#xff1b; 2. 國內的很多公有鏡像倉庫都被封了&#xff1b; 3. 推薦 https://zhuanlan.zhihu.com/p/713…

Codeforces Round 1008 (Div. 2) C

C 構造 題意&#xff1a;a的數據范圍大&#xff0c;b的數據范圍小&#xff0c;要求所有的a不同&#xff0c;考慮讓丟失的那個a最大即可。問題變成&#xff1a;構造一個最大的a[i] 思路&#xff1a;令a2是最大的,將a1,a3,a5....a2*n1&#xff0c;置為最大的b&#xff0c;將a4,a…

STM32 HAL庫實現USB虛擬串口

1. 引言 在嵌入式系統開發中&#xff0c;USB 虛擬串口是一種非常實用的功能。它允許 STM32 微控制器通過 USB 接口與計算機進行通信&#xff0c;就像使用傳統的串口一樣。這種方式不僅簡化了硬件設計&#xff0c;還提高了通信的靈活性和穩定性。STM32F407 系列微控制器具有強大…

JAVA EE_網絡原理_UDP與TCP

人海中未遇見時&#xff0c;我將獨自前行... ----------陳長生. 1.UDP協議 1.1.UDP協議端格式 UDP&#xff08;用戶數據報協議&#xff09;是由 源端口&#xff0c;目標端口&#xff0c;長度&#xff0c;校驗和&#xff0c;數據 5種結構組成。16位是UDP報文中字段的長度&#…

【免費】1992-2021年各省GDP數據/各省地區生產總值數據

1992-2021年各省GDP數據/各省地區生產總值數據 1、時間&#xff1a;1992-2021年 2、來源&#xff1a;國家統計局、統計年鑒 3、指標&#xff1a;GDP/地區生產總值 4、范圍&#xff1a;31省 5、指標說明:國內生產總值&#xff08;GDP&#xff09;是一個國家或地區在一定時期…

C++11新特性_范圍-based for 循環

based for 循環介紹 范圍 - based for 循環&#xff08;Range-based for loop&#xff09;是 C11 引入的一種新的 for 循環語法&#xff0c;它可以更簡潔地遍歷容器和數組。 遍歷數組&#xff1a;定義了一個整數數組 arr&#xff0c;使用范圍 - based for 循環 for (int num :…

【Bootstrap V4系列】學習入門教程之 頁面內容排版

Bootstrap V4 學習入門教程之 頁面內容排版 按鈕上的指針排版一、Global settings 全局設置二、Headings 標題2.1 Customizing headings 自定義標題2.2 Display headings 顯示標題2.3 Lead 引導 三、Blockquotes 塊引用3.1 Naming a source 命名源3.2 Alignment 對齊 四、Lists…

Flowable7.x學習筆記(十六)分頁查詢我的待辦

前言 我的待辦具體區分為3種情況&#xff0c;第一個就是辦理人指定就是我&#xff0c;我可以直接審批&#xff1b;第二種就是我是候選人&#xff0c;我需要先拾取任務然后再辦理&#xff1b;第三種是我是候選組&#xff0c;我需要切換到指定的角色去拾取任務再辦理。如果任務已…