新聞中心
TCP(Tranission Control Protocol)是一種網(wǎng)絡(luò)傳輸層協(xié)議,主要用于保證數(shù)據(jù)在網(wǎng)絡(luò)中可靠傳輸。在 Linux 操作系統(tǒng)中,TCP 協(xié)議是非常重要且廣泛使用的協(xié)議,因此深入了解 Linux TCP 將有助于我們更好地理解 Linux 網(wǎng)絡(luò)編程和網(wǎng)絡(luò)優(yōu)化。

我們提供的服務(wù)有:成都網(wǎng)站建設(shè)、網(wǎng)站制作、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、漢陽ssl等。為近1000家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的漢陽網(wǎng)站制作公司
本文將介紹一些常用的 Linux TCP 相關(guān)命令和工具,并通過一個(gè) TCP 客戶端和服務(wù)器的例子,深入了解 TCP 的基本流程和一些常見的 TCP 問題。
1. 常用 Linux TCP 命令和工具
1.1 netstat
netstat 命令是一個(gè)非常常用的網(wǎng)絡(luò)命令,可以用于顯示各種網(wǎng)絡(luò)信息。在查看 TCP 相關(guān)信息時(shí),我們可以使用以下命令來查看當(dāng)前連接的狀態(tài)信息:
“`bash
netstat -ant | grep ESTABLISHED
“`
該命令將顯示當(dāng)前所有已建立的連接信息,包括本地 IP 和端口號(hào)、遠(yuǎn)程 IP 和端口號(hào)、TCP 的狀態(tài)等信息。
1.2 tcpdump
tcpdump 是一個(gè)用于捕獲網(wǎng)絡(luò)數(shù)據(jù)包的命令行工具。通過 tcpdump,我們可以詳細(xì)查看網(wǎng)絡(luò)通信中的各種細(xì)節(jié)信息,包括TCP包的頭部信息、數(shù)據(jù)長(zhǎng)度、序列號(hào)、確認(rèn)號(hào)等等。例如,我們可以使用以下命令來捕獲指定端口的數(shù)據(jù)包:
“`bash
sudo tcpdump -n -i eth0 port 8080
“`
該命令將捕獲所有進(jìn)入或離開 eth0 接口上的 8080 端口的 TCP 數(shù)據(jù)包,并輸出詳細(xì)信息。
1.3 tcptrace
tcptrace 是一個(gè)用于分析和生成 TCP 連接數(shù)據(jù)包的工具。通過 tcptrace,我們可以詳細(xì)了解 TCP 連接的生命周期,了解各個(gè)階段的數(shù)據(jù)傳輸情況、時(shí)延、丟包等信息。例如,我們可以使用以下命令來生成 TCP 連接的日志文件:
“`bash
sudo tcpdump -n -s0 -w tcpdump.log port 8080
sudo tcptrace -xS tcpdump.log
“`
該命令將捕獲本地 8080 端口的所有 TCP 數(shù)據(jù)包,并將其轉(zhuǎn)儲(chǔ)到 tcpdump.log 文件中。然后我們可以使用 tcptrace 命令來分析生成數(shù)據(jù)文件。
2. TCP 客戶端和服務(wù)器的例子
在 Linux 中,我們可以使用各種編程語言來編寫 TCP 客戶端和服務(wù)器程序。下面,我們將使用 C 語言來編寫一個(gè)簡(jiǎn)單的 TCP 客戶端和服務(wù)器程序,并通過這個(gè)例子來深入了解 TCP 的基本流程和一些常見的 TCP 問題。
2.1 TCP 服務(wù)器
下面是一個(gè)簡(jiǎn)單的 TCP 服務(wù)器程序的示例代碼:
“`c
#include
#include
#include
#include
#include
#include
#include
#define PORT 8080
#define BACKLOG 10
int mn()
{
int sockfd, new_fd;
struct sockaddr_in my_addr;
struct sockaddr_in their_addr;
size_t sin_size;
char buf[1024];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror(“socket”);
exit(1);
}
my_addr.sin_family = AF_INET;
my_addr.sin_port = htons(PORT);
my_addr.sin_addr.s_addr = INADDR_ANY;
bzero(&(my_addr.sin_zero), 8);
if (bind(sockfd, (struct sockaddr *)&my_addr, sizeof(struct sockaddr)) == -1)
{
perror(“bind”);
exit(1);
}
if (listen(sockfd, BACKLOG) == -1)
{
perror(“l(fā)isten”);
exit(1);
}
printf(“server started listening on %d…\n”, PORT);
while (1)
{
if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, (socklen_t *)&sin_size)) == -1)
{
perror(“accept”);
continue;
}
printf(“server got connection from %s\n”, inet_ntoa(their_addr.sin_addr));
send(new_fd, “Hello, world!”, 13, 0);
close(new_fd);
}
close(sockfd);
return 0;
}
“`
上述代碼中,我們首先通過 socket 函數(shù)創(chuàng)建了一個(gè)套接字,然后通過 bind 函數(shù)將該套接字與本地的 IP 地址和端口號(hào)綁定。接著,我們調(diào)用 listen 函數(shù)開啟服務(wù),準(zhǔn)備接受來自 TCP 客戶端的連接請(qǐng)求。在主循環(huán)中,我們通過 accept 函數(shù)等待客戶端的連接請(qǐng)求,一旦接收到連接請(qǐng)求,就使用 send 函數(shù)向客戶端發(fā)送歡迎信息,并使用 close 函數(shù)關(guān)閉連接。
2.2 TCP 客戶端
下面是一個(gè)簡(jiǎn)單的 TCP 客戶端程序的示例代碼:
“`c
#include
#include
#include
#include
#include
#include
#include
#define PORT 8080
#define SERVER_ADDR “127.0.0.1”
int mn()
{
int sockfd;
struct sockaddr_in server_addr;
char buf[1024];
if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
perror(“socket”);
exit(1);
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = inet_addr(SERVER_ADDR);
bzero(&(server_addr.sin_zero), 8);
if (connect(sockfd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
perror(“connect”);
exit(1);
}
recv(sockfd, buf, 1024, 0);
printf(“client received: %s\n”, buf);
close(sockfd);
return 0;
}
“`
上述代碼中,我們同樣首先通過 socket 函數(shù)創(chuàng)建了一個(gè)套接字,然后通過 connect 函數(shù)連接到遠(yuǎn)程服務(wù)器的 IP 地址和端口號(hào)。在連接成功后,我們通過 recv 函數(shù)等待服務(wù)器的響應(yīng),并將其輸出到控制臺(tái)。我們通過 close 函數(shù)關(guān)閉連接。
3.
相關(guān)問題拓展閱讀:
- TCP那些事兒
- Linux TCP/IP協(xié)議棧數(shù)據(jù)包處理流程及代碼實(shí)現(xiàn)分析
TCP那些事兒
目錄:
以前畢盯洞我也認(rèn)為TCP是相當(dāng)?shù)讓拥臇|西,我永遠(yuǎn)不需要去了解它。雖然差不多是這樣,但是實(shí)際生活中,你依然可能遇見和TCP算法相關(guān)的bug,這時(shí)候懂一些TCP的知識(shí)就至關(guān)重要了。(
本文也可以引申為,系統(tǒng)調(diào)用,操作系統(tǒng)這些都很重要,這個(gè)道理適用于很多東西
)
這里推薦一篇小短文, 人人都應(yīng)該懂點(diǎn)TCP
使用TCP協(xié)議通信的雙方必須先建立TCP連接,并在內(nèi)核中為該連接維持一些必要的數(shù)據(jù)結(jié)構(gòu),比如連接的狀態(tài)、讀寫緩沖區(qū)、定時(shí)器等。當(dāng)通信結(jié)束時(shí),雙方必須關(guān)閉連接以釋放這些內(nèi)核數(shù)據(jù)。TCP服務(wù)基于流,源源不斷從一端流向另一端,發(fā)送端可以逐字節(jié)寫入,接收端可以逐字節(jié)讀出,無需分段。
需要注意的幾點(diǎn):
TCP狀態(tài)(11種):
eg.
以上為TCP三次握手的狀態(tài)變遷
以下為TCP四次揮手的狀態(tài)變遷
服務(wù)器通過 listen 系統(tǒng)調(diào)用進(jìn)入
LISTEN
狀態(tài),被動(dòng)等待客戶端連接,也就是所謂的被動(dòng)打開。一旦監(jiān)聽到SYN(同步報(bào)文段)請(qǐng)求,就將該連接放入內(nèi)核的等待隊(duì)列,并向客戶端發(fā)送帶SYN的ACK(確認(rèn)報(bào)文段),此時(shí)該連接處于
SYN_RECVD
狀態(tài)。如果服務(wù)器收到客戶端返回的ACK,則轉(zhuǎn)到
ESTABLISHED
狀態(tài)。這個(gè)狀態(tài)就是連接雙方能進(jìn)行全雙工數(shù)據(jù)傳輸?shù)臓顟B(tài)。
而當(dāng)客戶端主動(dòng)關(guān)閉連接時(shí),服務(wù)器收到FIN報(bào)文,通過返回ACK使連接進(jìn)入
CLOSE_WAIT
狀態(tài)。此狀態(tài)表示——等待服務(wù)器應(yīng)用程序關(guān)閉連接。通常,服務(wù)器檢測(cè)到客戶端關(guān)閉連接之后,也會(huì)立即給客戶端發(fā)送一個(gè)FIN來關(guān)閉連接,使連接轉(zhuǎn)移到
LAST_ACK
狀態(tài),等待客戶端對(duì)最后一個(gè)FIN結(jié)束報(bào)文段的最后一次確認(rèn),一旦確認(rèn)完成,連接就徹底關(guān)閉了。
客戶端通過 connect 系統(tǒng)調(diào)用主動(dòng)與服務(wù)器建立連接。此系統(tǒng)調(diào)用會(huì)首先給服務(wù)器發(fā)一個(gè)SYN,使連接進(jìn)入
SYN_SENT
狀態(tài)。
connect 調(diào)用可能因?yàn)閮煞N原因失?。?. 目標(biāo)端口不存在(未被任何進(jìn)程監(jiān)聽)護(hù)著該端口被
TIME_WAIT
狀態(tài)的連接占用( 詳見后文 )。2. 連接超時(shí),在超時(shí)時(shí)間內(nèi)未收到服務(wù)器的ACK。
如果 connect 調(diào)用失敗,則連接返回初始的
CLOSED
狀態(tài),如果調(diào)用成功,則轉(zhuǎn)到
ESTABLISHED
狀態(tài)。
客戶端執(zhí)行主動(dòng)關(guān)閉時(shí),它會(huì)向服務(wù)器發(fā)送一個(gè)FIN,連接進(jìn)入
TIME_WAIT_1
狀態(tài),如果收到服務(wù)器的ACK,進(jìn)入
TIME_WAIT_2
狀態(tài)。此時(shí)服務(wù)器處于
CLOSE_WAIT
狀態(tài),這一對(duì)狀態(tài)是可能發(fā)生辦關(guān)閉的狀態(tài)(詳見后文)。此時(shí)如果服務(wù)器發(fā)送FIN關(guān)閉連接,則客戶端會(huì)發(fā)送ACK進(jìn)行確認(rèn)并進(jìn)入
TIME_WAIT
狀態(tài)。
流量控制是為了控制發(fā)送方發(fā)送速率,保證接收方來得及接收。
接收方發(fā)送的確認(rèn)報(bào)文中的窗口字段可以用來控制發(fā)送方窗口大小,從而影響發(fā)送方的發(fā)送速率。將窗口字段設(shè)置為 0,則發(fā)送方不能發(fā)送數(shù)據(jù)。
如果網(wǎng)絡(luò)出現(xiàn)擁塞,分組將會(huì)丟失,此時(shí)發(fā)送方會(huì)繼續(xù)重傳手枯,從而導(dǎo)致網(wǎng)絡(luò)擁塞程度更高。因此當(dāng)出現(xiàn)擁塞時(shí),應(yīng)當(dāng)控制發(fā)送方的速率。這一點(diǎn)和流量控制很像,但是出發(fā)點(diǎn)不同。
流量控制是為了讓接收方能來得及接收,而擁塞控制是為了降低整個(gè)網(wǎng)絡(luò)的擁塞程度。
TCP 主要通過四種算法來進(jìn)行擁塞控制:
慢開始、擁塞避免、快重傳、快恢復(fù)。
在Linux下有多種則埋實(shí)現(xiàn),比如reno算法,vegas算法和cubic算法等。
發(fā)送方需要維護(hù)一個(gè)叫做擁塞窗口(cwnd)的狀態(tài)變量,注意擁塞窗口與發(fā)送方窗口的區(qū)別:擁塞窗口只是一個(gè)狀態(tài)變量,實(shí)際決定發(fā)送方能發(fā)送多少數(shù)據(jù)的是發(fā)送方窗口。
為了便于討論,做如下假設(shè):
發(fā)送的最初執(zhí)行慢開始,令 cwnd=1,發(fā)送方只能發(fā)送 1 個(gè)報(bào)文段;當(dāng)收到確認(rèn)后,將 cwnd 加倍,因此之后發(fā)送方能夠發(fā)送的報(bào)文段數(shù)量為:2、4、8 …
注意到慢開始每個(gè)輪次都將 cwnd 加倍,這樣會(huì)讓 cwnd 增長(zhǎng)速度非???,從而使得發(fā)送方發(fā)送的速度增長(zhǎng)速度過快,網(wǎng)絡(luò)擁塞的可能也就更高。設(shè)置一個(gè)慢開始門限 ssthresh,當(dāng) cwnd >= ssthresh 時(shí),進(jìn)入擁塞避免,每個(gè)輪次只將 cwnd 加 1。
如果出現(xiàn)了超時(shí),則令 ssthresh = cwnd/2,然后重新執(zhí)行慢開始。
在接收方,要求每次接收到報(bào)文段都應(yīng)該對(duì)最后一個(gè)已收到的有序報(bào)文段進(jìn)行確認(rèn)。例如已經(jīng)接收到 M1 和 M2,此時(shí)收到 M4,應(yīng)當(dāng)發(fā)送對(duì) M2 的確認(rèn)。
在發(fā)送方,如果收到三個(gè)重復(fù)確認(rèn),那么可以知道下一個(gè)報(bào)文段丟失,此時(shí)執(zhí)行快重傳,立即重傳下一個(gè)報(bào)文段。例如收到三個(gè) M2,則 M3 丟失,立即重傳 M3。
在這種情況下,只是丟失個(gè)別報(bào)文段,而不是網(wǎng)絡(luò)擁塞。因此執(zhí)行快恢復(fù),令 ssthresh = cwnd/2 ,cwnd = ssthresh,注意到此時(shí)直接進(jìn)入擁塞避免。
慢開始和快恢復(fù)的快慢指的是 cwnd 的設(shè)定值,而不是 cwnd 的增長(zhǎng)速率。慢開始 cwnd 設(shè)定為 1,而快恢復(fù) cwnd 設(shè)定為 ssthresh。
??發(fā)送端的每個(gè)TCP報(bào)文都必須得到接收方的應(yīng)答,才算傳輸成功。
??TCP為每個(gè)TCP報(bào)文段都維護(hù)一個(gè)重傳定時(shí)器。
??發(fā)送端在發(fā)出一個(gè)TCP報(bào)文段之后就啟動(dòng)定時(shí)器,如果在定時(shí)時(shí)間類未收到應(yīng)答,它就將重發(fā)該報(bào)文段并重置定時(shí)器。
??因?yàn)門CP報(bào)文段最終在網(wǎng)絡(luò)層是以IP數(shù)據(jù)報(bào)的形式發(fā)送,而IP數(shù)據(jù)報(bào)到達(dá)接收端可能是亂序或者重復(fù)的。TCP協(xié)議會(huì)對(duì)收到的TCP報(bào)文進(jìn)行重排、整理,確保順序正確。
TCP報(bào)文段所攜帶的應(yīng)用程序數(shù)據(jù)按照長(zhǎng)度分為兩種:
交互數(shù)據(jù)
和
成塊數(shù)據(jù)
對(duì)于什么是粘包、拆包問題,我想先舉兩個(gè)簡(jiǎn)單的應(yīng)用場(chǎng)景:
對(duì)于之一種情況,服務(wù)端的處理流程可以是這樣的:當(dāng)客戶端與服務(wù)端的連接建立成功之后,服務(wù)端不斷讀取客戶端發(fā)送過來的數(shù)據(jù),當(dāng)客戶端與服務(wù)端連接斷開之后,服務(wù)端知道已經(jīng)讀完了一條消息,然后進(jìn)行解碼和后續(xù)處理…。對(duì)于第二種情況,如果按照上面相同的處理邏輯來處理,那就有問題了,我們來看看
第二種情況
下客戶端發(fā)送的兩條消息遞交到服務(wù)端有可能出現(xiàn)的情況:
之一種情況:
服務(wù)端一共讀到兩個(gè)數(shù)據(jù)包,之一個(gè)包包含客戶端發(fā)出的之一條消息的完整信息,第二個(gè)包包含客戶端發(fā)出的第二條消息,那這種情況比較好處理,服務(wù)器只需要簡(jiǎn)單的從網(wǎng)絡(luò)緩沖區(qū)去讀就好了,之一次讀到之一條消息的完整信息,消費(fèi)完再?gòu)木W(wǎng)絡(luò)緩沖區(qū)將第二條完整消息讀出來消費(fèi)。
第二種情況:
服務(wù)端一共就讀到一個(gè)數(shù)據(jù)包,這個(gè)數(shù)據(jù)包包含客戶端發(fā)出的兩條消息的完整信息,這個(gè)時(shí)候基于之前邏輯實(shí)現(xiàn)的服務(wù)端就蒙了,因?yàn)榉?wù)端不知道之一條消息從哪兒結(jié)束和第二條消息從哪兒開始,這種情況其實(shí)是發(fā)生了TCP粘包。
第三種情況:
服務(wù)端一共收到了兩個(gè)數(shù)據(jù)包,之一個(gè)數(shù)據(jù)包只包含了之一條消息的一部分,之一條消息的后半部分和第二條消息都在第二個(gè)數(shù)據(jù)包中,或者是之一個(gè)數(shù)據(jù)包包含了之一條消息的完整信息和第二條消息的一部分信息,第二個(gè)數(shù)據(jù)包包含了第二條消息的剩下部分,這種情況其實(shí)是發(fā)送了TCP拆,因?yàn)榘l(fā)生了一條消息被拆分在兩個(gè)包里面發(fā)送了,同樣上面的服務(wù)器邏輯對(duì)于這種情況是不好處理的。
我們知道tcp是以流動(dòng)的方式傳輸數(shù)據(jù),傳輸?shù)淖钚挝粸橐粋€(gè)報(bào)文段(segment)。tcp Header中有個(gè)Options標(biāo)識(shí)位,常見的標(biāo)識(shí)為mss(Maximum Segment Size)指的是,連接層每次傳輸?shù)臄?shù)據(jù)有個(gè)更大限制MTU(Maximum Tranission Unit),一般是1500比特,超過這個(gè)量要分成多個(gè)報(bào)文段,mss則是這個(gè)更大限制減去TCP的header,光是要傳輸?shù)臄?shù)據(jù)的大小,一般為1460比特。換算成字節(jié),也就是180多字節(jié)。
tcp為提高性能,發(fā)送端會(huì)將需要發(fā)送的數(shù)據(jù)發(fā)送到緩沖區(qū),等待緩沖區(qū)滿了之后,再將緩沖中的數(shù)據(jù)發(fā)送到接收方。同理,接收方也有緩沖區(qū)這樣的機(jī)制,來接收數(shù)據(jù)。
發(fā)生TCP粘包、拆包主要是由于下面一些原因:
既然知道了tcp是無界的數(shù)據(jù)流,且協(xié)議本身無法避免粘包,拆包的發(fā)生,那我們只能在應(yīng)用層數(shù)據(jù)協(xié)議上,加以控制。通常在制定傳輸數(shù)據(jù)時(shí),可以使用如下方法:
寫了一個(gè)簡(jiǎn)單的 golang 版的tcp服務(wù)器實(shí)例,僅供參考:
例子
參考和推薦閱讀書目:
注釋:
eg.
Linux TCP/IP協(xié)議棧數(shù)據(jù)包處理流程及代碼實(shí)現(xiàn)分析
好吧,我來回答吧,首先是網(wǎng)卡驅(qū)動(dòng)程序捕銀衡獲到數(shù)據(jù)包,做檢驗(yàn)無誤后,和DMA以及CPU交互,然后由DMA和驅(qū)動(dòng)程序創(chuàng)建BD表,然后分配skbuf(LINUX下)數(shù)據(jù)結(jié)構(gòu)保存獲得的數(shù)據(jù)幀,內(nèi)核通過協(xié)議棧處理這個(gè)skbuf,通常是層層剝離每個(gè)層的首部,然后傳到上一層,細(xì)節(jié)就是一個(gè)變量做偏移量,每次做一個(gè)首部偏移讀取租搏鍵首部數(shù)據(jù),識(shí)別本層協(xié)議類型以及下一層協(xié)議類型,具體過程就是這個(gè)網(wǎng)絡(luò)原理的過程,請(qǐng)參考《TCP/IP詳解卷一》《linux設(shè)備驅(qū)動(dòng)程序》《understanding linux network internals》弊巧《Unix網(wǎng)絡(luò)編程卷一》等。
太高聲了
】
關(guān)于linux tcp例子的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
創(chuàng)新互聯(lián)服務(wù)器托管擁有成都T3+級(jí)標(biāo)準(zhǔn)機(jī)房資源,具備完善的安防設(shè)施、三線及BGP網(wǎng)絡(luò)接入帶寬達(dá)10T,機(jī)柜接入千兆交換機(jī),能夠有效保證服務(wù)器托管業(yè)務(wù)安全、可靠、穩(wěn)定、高效運(yùn)行;創(chuàng)新互聯(lián)專注于成都服務(wù)器托管租用十余年,得到成都等地區(qū)行業(yè)客戶的一致認(rèn)可。
當(dāng)前文章:深入了解LinuxTCP的例子(linuxtcp例子)
網(wǎng)站鏈接:http://m.fisionsoft.com.cn/article/djioojh.html


咨詢
建站咨詢
