新聞中心
隨著現(xiàn)代網(wǎng)絡(luò)系統(tǒng)的不斷發(fā)展,網(wǎng)絡(luò)安全越來(lái)越成為企業(yè)、機(jī)構(gòu)和個(gè)人重要的關(guān)注點(diǎn)。為了更好地維護(hù)網(wǎng)絡(luò)環(huán)境安全,Linux系統(tǒng)給出了心跳包技術(shù)。在網(wǎng)絡(luò)連接過(guò)程中,如果設(shè)備出現(xiàn)故障,心跳包技術(shù)可以檢測(cè)出具體的設(shè)備,并及時(shí)通知管理員進(jìn)行處理。

成都創(chuàng)新互聯(lián)公司專注于景縣網(wǎng)站建設(shè)服務(wù)及定制,我們擁有豐富的企業(yè)做網(wǎng)站經(jīng)驗(yàn)。 熱誠(chéng)為您提供景縣營(yíng)銷型網(wǎng)站建設(shè),景縣網(wǎng)站制作、景縣網(wǎng)頁(yè)設(shè)計(jì)、景縣網(wǎng)站官網(wǎng)定制、成都微信小程序服務(wù),打造景縣網(wǎng)絡(luò)公司原創(chuàng)品牌,更為您提供景縣網(wǎng)站排名全網(wǎng)營(yíng)銷落地服務(wù)。
本文將為你介紹。
1. 心跳包的概念
心跳包技術(shù)利用持續(xù)發(fā)送的數(shù)據(jù)包測(cè)試網(wǎng)絡(luò)設(shè)備是否存活或處于聯(lián)網(wǎng)狀態(tài)。心跳數(shù)據(jù)包可以通過(guò)多種傳輸協(xié)議進(jìn)行發(fā)送,如TCP、UDP等。
心跳包技術(shù)主要解決以下問(wèn)題:
– 監(jiān)測(cè)網(wǎng)絡(luò)設(shè)備是否存活。
– 提供故障檢測(cè)和異常處理機(jī)制。
– 進(jìn)行網(wǎng)絡(luò)流量控制。
2. Linux系統(tǒng)的心跳包
Linux內(nèi)核提供了一種心跳包實(shí)現(xiàn)機(jī)制。當(dāng)心跳包發(fā)送應(yīng)答時(shí),系統(tǒng)會(huì)按照指定時(shí)間間隔生成心跳包數(shù)據(jù)并發(fā)送出去。如果在設(shè)定的時(shí)間內(nèi)沒(méi)有回應(yīng),系統(tǒng)會(huì)認(rèn)為網(wǎng)絡(luò)出現(xiàn)了問(wèn)題,并進(jìn)一步確認(rèn)損壞的設(shè)備或網(wǎng)絡(luò)節(jié)點(diǎn)。
同時(shí),Linux系統(tǒng)還支持幾種心跳包協(xié)議。
2.1 ICMP協(xié)議
ICMP(Internet Control Message Protocol)協(xié)議是Linux系統(tǒng)默認(rèn)使用的協(xié)議。在進(jìn)行ping測(cè)試時(shí),就是通過(guò)ICMP協(xié)議生成相應(yīng)的心跳包。ICMP控制信息包常常用于網(wǎng)絡(luò)層和傳輸層之間的協(xié)議。
2.2 UDP協(xié)議
UDP(User Datagram Protocol)協(xié)議是一種無(wú)連接的協(xié)議,不保證可靠傳輸,但是在一些實(shí)時(shí)性要求較高的應(yīng)用場(chǎng)景下有更好的表現(xiàn)。
2.3 TCP協(xié)議
TCP(Tranission Control Protocol)協(xié)議是一種面向連接的協(xié)議,在進(jìn)行可靠傳輸時(shí)更為可靠,但也更為復(fù)雜。TCP協(xié)議主要用于HTTP、FTP等協(xié)議的傳輸中。
3. 心跳包C語(yǔ)言實(shí)現(xiàn)
為了更好地實(shí)現(xiàn)心跳包檢測(cè),我們可以使用C語(yǔ)言進(jìn)行相關(guān)程序設(shè)計(jì)。
3.1 心跳包生成
生成心跳包的過(guò)程,通過(guò)設(shè)置發(fā)送方和接收方地址信息,以及具體的心跳包內(nèi)容來(lái)實(shí)現(xiàn)。
示例代碼:
“`
struct sockaddr_in dest_addr;
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons(port);
dest_addr.sin_addr.s_addr = inet_addr(ip);
const char* data = “Hello world!”;
int data_len = strlen(data);
sendto(sockfd, data, data_len, 0, (struct sockaddr*)&dest_addr, sizeof(dest_addr));
“`
3.2 心跳監(jiān)測(cè)
接收方可以使用select或epoll等系統(tǒng)調(diào)用來(lái)實(shí)現(xiàn)心跳包的監(jiān)聽(tīng)。這些系統(tǒng)調(diào)用可以同時(shí)監(jiān)聽(tīng)多個(gè)套接字,有效提高系統(tǒng)處理效率。
示例代碼:
“`
// add sockfd to epoll
…
while (true) {
epoll_wt(epoll_fd, events, max_events, timeout);
for (int i = 0; i
int sockfd = events[i].data.fd;
memset(buf, 0, MAX_BUFFER_SIZE);
ssize_t recv_len = recvfrom(sockfd, buf, MAX_BUFFER_SIZE, 0, (struct sockaddr*)&addr, &addr_len);
// check if recv_buf is heartbeat data
…
}
}
“`
4.
通過(guò)本文,我們了解了心跳包的基本概念和Linux系統(tǒng)的心跳包實(shí)現(xiàn)機(jī)制。同時(shí),我們還通過(guò)C語(yǔ)言代碼展示了如何實(shí)現(xiàn)心跳包的生成和監(jiān)測(cè)。
心跳包技術(shù)在網(wǎng)絡(luò)安全和網(wǎng)絡(luò)連接穩(wěn)定性方面都有重要的作用。希望本文能夠?yàn)榇蠹姨峁┮恍﹨⒖己蛯?shí)踐的指導(dǎo)。
相關(guān)問(wèn)題拓展閱讀:
- 如何在linux環(huán)境下實(shí)現(xiàn)客戶端和服務(wù)器之間
- 一篇搞懂tcp,http,socket,socket連接池之間的關(guān)系
如何在linux環(huán)境下實(shí)現(xiàn)客戶端和服務(wù)器之間
網(wǎng)絡(luò)的Socket數(shù)據(jù)傳輸是一種特殊的I/O,Socket也是一種文件描述符。Socket也具有一個(gè)類似于打開(kāi)文件肆螞斗的函數(shù)調(diào)用Socket(),該函數(shù)返回一個(gè)整型的Socket描述符,隨后的連接建立、數(shù)據(jù)傳輸?shù)炔僮鞫际峭ㄟ^(guò)物喊該Socket實(shí)現(xiàn)的。
下面用Socket實(shí)現(xiàn)一個(gè)windows下的c語(yǔ)言socket通信例子,這里我們客戶端傳遞一個(gè)字裂磨符串,服務(wù)器端進(jìn)行接收。
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
【服務(wù)器端】
#include “stdafx.h”
#include
#include
#include
#define SERVER_PORT 5208 //偵聽(tīng)端口
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int ret, nLeft, length;
SOCKET sListen, sServer; //偵聽(tīng)套接字,連接套接字
struct sockaddr_in saServer, saClient; //地址信息
char *ptr;//用于遍歷信息的指針
//WinSock初始化
wVersionRequested=MAKEWORD(2, 2); //希望使用的WinSock DLL 的版本
ret=WSAStartup(wVersionRequested, &wsaData);
if(ret!=0)
{
printf(“WSAStartup() failed!\n”);
return;
}
//創(chuàng)建Socket,使用TCP協(xié)議
sListen=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sListen == INVALID_SOCKET)
{
WSACleanup();
printf(“socket() faild!\n”);
return;
}
//構(gòu)建本地地址信息
saServer.sin_family = AF_INET; //地址家族
saServer.sin_port = htons(SERVER_PORT); //注意轉(zhuǎn)化為網(wǎng)絡(luò)字節(jié)序
saServer.sin_addr.S_un.S_addr = htonl(INADDR_ANY); //使用INADDR_ANY 指示任意地址
//綁定
ret = bind(sListen, (struct sockaddr *)&saServer, sizeof(saServer));
if (ret == SOCKET_ERROR)
{
printf(“bind() faild! code:%d\n”, WSAGetLastError());
closesocket(sListen); //關(guān)閉套接字
WSACleanup();
return;
}
//偵聽(tīng)連接請(qǐng)求
ret = listen(sListen, 5);
if (ret == SOCKET_ERROR)
{
printf(“l(fā)isten() faild! code:%d\n”, WSAGetLastError());
closesocket(sListen); //關(guān)閉套接字
return;
}
printf(“Waiting for client connecting!\n”);
printf(“Tips: Ctrl+c to quit!\n”);
//阻塞等待接受客戶端連接
while(1)//循環(huán)監(jiān)聽(tīng)客戶端,永遠(yuǎn)不停止,所以,在本項(xiàng)目中,我們沒(méi)有心跳包。
{
length = sizeof(saClient);
sServer = accept(sListen, (struct sockaddr *)&saClient, &length);
if (sServer == INVALID_SOCKET)
{
printf(“accept() faild! code:%d\n”, WSAGetLastError());
closesocket(sListen); //關(guān)閉套接字
WSACleanup();
return;
}
char receiveMessage;
nLeft = sizeof(receiveMessage);
ptr = (char *)&receiveMessage;
while(nLeft>0)
{
//接收數(shù)據(jù)
ret = recv(sServer, ptr, 5000, 0);
if (ret == SOCKET_ERROR)
{
printf(“recv() failed!\n”);
return;
}
if (ret == 0) //客戶端已經(jīng)關(guān)閉連接
{
printf(“Client has closed the connection\n”);
break;
}
nLeft -= ret;
ptr += ret;
}
printf(“receive message:%s\n”, receiveMessage);//打印我們接收到的消息。
}
// closesocket(sListen);
// closesocket(sServer);
// WSACleanup();
}
【客戶端】
#include “stdafx.h”
#include
#include
#include
#define SERVER_PORT 5208 //偵聽(tīng)端口
void main()
{
WORD wVersionRequested;
WSADATA wsaData;
int ret;
SOCKET sClient; //連接套接字
struct sockaddr_in saServer; //地址信息
char *ptr;
BOOL fSuccess = TRUE;
//WinSock初始化
wVersionRequested = MAKEWORD(2, 2); //希望使用的WinSock DLL的版本
ret = WSAStartup(wVersionRequested, &wsaData);
if(ret!=0)
{
printf(“WSAStartup() failed!\n”);
return;
}
//確認(rèn)WinSock DLL支持版本2.2
if(LOBYTE(wsaData.wVersion)!=2 || HIBYTE(wsaData.wVersion)!=2)
{
WSACleanup();
printf(“Invalid WinSock version!\n”);
return;
}
//創(chuàng)建Socket,使用TCP協(xié)議
sClient = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (sClient == INVALID_SOCKET)
{
WSACleanup();
printf(“socket() failed!\n”);
return;
}
//構(gòu)建服務(wù)器地址信息
saServer.sin_family = AF_INET; //地址家族
saServer.sin_port = htons(SERVER_PORT); //注意轉(zhuǎn)化為網(wǎng)絡(luò)節(jié)序
saServer.sin_addr.S_un.S_addr = inet_addr(“192.168.1.127”);
//連接服務(wù)器
ret = connect(sClient, (struct sockaddr *)&saServer, sizeof(saServer));
if (ret == SOCKET_ERROR)
{
printf(“connect() failed!\n”);
closesocket(sClient); //關(guān)閉套接字
WSACleanup();
return;
}
char sendMessage=”hello this is client message!”;
ret = send (sClient, (char *)&sendMessage, sizeof(sendMessage), 0);
if (ret == SOCKET_ERROR)
{
printf(“send() failed!\n”);
}
else
printf(“client info has been sent!”);
closesocket(sClient); //關(guān)閉套接字
WSACleanup();
一篇搞懂tcp,http,socket,socket連接池之間的關(guān)系
作為一名開(kāi)發(fā)人員我們經(jīng)常會(huì)聽(tīng)到HTTP協(xié)議、TCP/IP協(xié)議、UDP協(xié)議、Socket、Socket長(zhǎng)連接、Socket連接池等字眼,然而它們之間的關(guān)系、區(qū)別及原理并不是所有人都能理解清楚,這篇文章就從網(wǎng)絡(luò)協(xié)議基礎(chǔ)開(kāi)始到Socket連接池,一步一步解釋他們之間的關(guān)系。
首先從網(wǎng)絡(luò)通信的分層模型講起:七層模型,亦稱OSI(Open System Interconnection)模型。自下往上分為:物理層、數(shù)據(jù)鏈路層、網(wǎng)絡(luò)層、傳輸層、會(huì)話層、表示層和應(yīng)用層。所有有關(guān)通信的都離不開(kāi)它,下面這張圖片介紹了各層所對(duì)應(yīng)的一些協(xié)議和硬件
通過(guò)上圖,我知道IP協(xié)議對(duì)應(yīng)于網(wǎng)絡(luò)層,TCP、UDP協(xié)議對(duì)應(yīng)于傳輸層,而HTTP協(xié)議對(duì)應(yīng)于應(yīng)用層,OSI并沒(méi)有Socket,那什么是Socket,后面我們將結(jié)合代碼具體詳細(xì)介紹。
關(guān)于傳輸層TCP、UDP協(xié)議可能我們平時(shí)遇見(jiàn)的會(huì)比較多,有人說(shuō)TCP是安全的,UDP是不安全的,UDP傳輸比TCP快,那為什么呢,我們先從TCP的連接建立的過(guò)程開(kāi)始分析,然后解釋UDP和TCP的區(qū)別。
TCP的三次握手和四次分手
我們知道TCP建立連接需要經(jīng)過(guò)三次握手,而斷開(kāi)連接需要經(jīng)過(guò)四次分手,那三次握手和四次分手分別做了什么和如何進(jìn)行的。
之一次握手:
建立連接??蛻舳税l(fā)送連接請(qǐng)求報(bào)文段,將SYN位置為1,Sequence Number為x;然后,客戶端進(jìn)入SYN_SEND狀態(tài),等待服務(wù)器的確認(rèn);
第二次握手:
服務(wù)器收到客戶端的SYN報(bào)文段,需要對(duì)這個(gè)SYN報(bào)文段進(jìn)行確認(rèn),設(shè)置Acknowledgment Number為x+1(Sequence Number+1);同時(shí),明含自己自己還要發(fā)送SYN請(qǐng)求信息,將SYN位置為1,Sequence Number為y;服務(wù)器端將上述所有信息放到一個(gè)報(bào)文段(即SYN+ACK報(bào)文段)中,一并發(fā)送給客戶端,此時(shí)服務(wù)器進(jìn)入SYN_RECV狀態(tài);
第三次握手:
客戶端收到服務(wù)器的SYN+ACK報(bào)文段。然后將Acknowledgment Number設(shè)置為y+1,向服務(wù)器發(fā)送ACK報(bào)文段,這個(gè)報(bào)文段發(fā)送完畢以后,客戶端和服務(wù)器端都進(jìn)入ESTABLISHED狀態(tài),完成TCP三次握手。
完成了三次握手,客戶端和服務(wù)器端就可以開(kāi)始傳送數(shù)據(jù)。以上就是TCP三次握手的總體介紹。通信結(jié)束客戶端和服務(wù)端就斷開(kāi)連接,需要經(jīng)過(guò)四次分手確認(rèn)。
之一次分手:
主機(jī)1(可以使客戶端,也可以是服務(wù)器端),設(shè)置Sequence Number和Acknowledgment Number,向主機(jī)2發(fā)送一個(gè)FIN報(bào)文段;此時(shí),主機(jī)1進(jìn)入FIN_WAIT_1狀態(tài);這表示主機(jī)1沒(méi)有數(shù)據(jù)要發(fā)送給主機(jī)2了;
第二次分手:
主機(jī)2收到了主機(jī)1發(fā)送的FIN報(bào)文段,向主機(jī)1回一個(gè)ACK報(bào)文段,Acknowledgment Number為Sequence Number加1;主機(jī)1進(jìn)入FIN_WAIT_2狀態(tài);主機(jī)2告訴主機(jī)1,我“同意”你的關(guān)閉請(qǐng)求;
第三次分手:
主機(jī)2向主機(jī)1發(fā)送FIN報(bào)文段,請(qǐng)求關(guān)閉連接,同時(shí)主機(jī)2進(jìn)入LAST_ACK狀態(tài);
第四次分手
:主機(jī)1收到主機(jī)2發(fā)送的FIN報(bào)文段,向主機(jī)2發(fā)送ACK報(bào)文段,然后主機(jī)1進(jìn)入TIME_WAIT狀態(tài);主機(jī)2收到主機(jī)1的ACK報(bào)文段以后,就關(guān)閉連接;此時(shí),主激橋笑機(jī)1等待2MSL后依然沒(méi)有收到回復(fù),則證明Server端已正常關(guān)閉,那好,主機(jī)1也可以關(guān)閉連接了。
可以看到一次tcp請(qǐng)求的建立及關(guān)閉至少進(jìn)行7次通信,這還不包過(guò)數(shù)據(jù)的通信,而UDP不需3次握手和4次分手。
TCP和UDP的區(qū)別
1、TCP是面向鏈接的,雖然說(shuō)網(wǎng)絡(luò)的不安全不穩(wěn)定特性決定了多少次握手都不能保證連接的可靠性,但TCP的三次握手在更低限度上(實(shí)際上也很大程度上保證了)保證了連接的消此可靠性;而UDP不是面向連接的,UDP傳送數(shù)據(jù)前并不與對(duì)方建立連接,對(duì)接收到的數(shù)據(jù)也不發(fā)送確認(rèn)信號(hào),發(fā)送端不知道數(shù)據(jù)是否會(huì)正確接收,當(dāng)然也不用重發(fā),所以說(shuō)UDP是無(wú)連接的、不可靠的一種數(shù)據(jù)傳輸協(xié)議?!?/p>
2、也正由于1所說(shuō)的特點(diǎn),使得UDP的開(kāi)銷更小數(shù)據(jù)傳輸速率更高,因?yàn)椴槐剡M(jìn)行收發(fā)數(shù)據(jù)的確認(rèn),所以UDP的實(shí)時(shí)性更好。知道了TCP和UDP的區(qū)別,就不難理解為何采用TCP傳輸協(xié)議的MSN比采用UDP的QQ傳輸文件慢了,但并不能說(shuō)QQ的通信是不安全的,因?yàn)槌绦騿T可以手動(dòng)對(duì)UDP的數(shù)據(jù)收發(fā)進(jìn)行驗(yàn)證,比如發(fā)送方對(duì)每個(gè)數(shù)據(jù)包進(jìn)行編號(hào)然后由接收方進(jìn)行驗(yàn)證啊什么的,即使是這樣,UDP因?yàn)樵诘讓訁f(xié)議的封裝上沒(méi)有采用類似TCP的“三次握手”而實(shí)現(xiàn)了TCP所無(wú)法達(dá)到的傳輸效率。
關(guān)于傳輸層我們會(huì)經(jīng)常聽(tīng)到一些問(wèn)題
1.TCP服務(wù)器更大并發(fā)連接數(shù)是多少?
關(guān)于TCP服務(wù)器更大并發(fā)連接數(shù)有一種誤解就是“因?yàn)槎丝谔?hào)上限為65535,所以TCP服務(wù)器理論上的可承載的更大并發(fā)連接數(shù)也是65535”。首先需要理解一條TCP連接的組成部分:
客戶端IP、客戶端端口、服務(wù)端IP、服務(wù)端端口
。所以對(duì)于TCP服務(wù)端進(jìn)程來(lái)說(shuō),他可以同時(shí)連接的客戶端數(shù)量并不受限于可用端口號(hào),理論上一個(gè)服務(wù)器的一個(gè)端口能建立的連接數(shù)是全球的IP數(shù)*每臺(tái)機(jī)器的端口數(shù)。實(shí)際并發(fā)連接數(shù)受限于linux可打開(kāi)文件數(shù),這個(gè)數(shù)是可以配置的,可以非常大,所以實(shí)際上受限于系統(tǒng)性能。通過(guò)#ulimit -n 查看服務(wù)的更大文件句柄數(shù),通過(guò)ulimit -n xxx 修改 xxx是你想要能打開(kāi)的數(shù)量。也可以通過(guò)修改系統(tǒng)參數(shù):
2.為什么TIME_WAIT狀態(tài)還需要等2MSL后才能返回到CLOSED狀態(tài)?
這是因?yàn)殡m然雙方都同意關(guān)閉連接了,而且握手的4個(gè)報(bào)文也都協(xié)調(diào)和發(fā)送完畢,按理可以直接回到CLOSED狀態(tài)(就好比從SYN_SEND狀態(tài)到ESTABLISH狀態(tài)那樣);但是因?yàn)槲覀儽仨氁傧刖W(wǎng)絡(luò)是不可靠的,你無(wú)法保證你最后發(fā)送的ACK報(bào)文會(huì)一定被對(duì)方收到,因此對(duì)方處于LAST_ACK狀態(tài)下的Socket可能會(huì)因?yàn)槌瑫r(shí)未收到ACK報(bào)文,而重發(fā)FIN報(bào)文,所以這個(gè)TIME_WAIT狀態(tài)的作用就是用來(lái)重發(fā)可能丟失的ACK報(bào)文。
3.TIME_WAIT狀態(tài)還需要等2MSL后才能返回到CLOSED狀態(tài)會(huì)產(chǎn)生什么問(wèn)題
通信雙方建立TCP連接后,主動(dòng)關(guān)閉連接的一方就會(huì)進(jìn)入TIME_WAIT狀態(tài),TIME_WAIT狀態(tài)維持時(shí)間是兩個(gè)MSL時(shí)間長(zhǎng)度,也就是在1-4分鐘,Windows操作系統(tǒng)就是4分鐘。進(jìn)入TIME_WAIT狀態(tài)的一般情況下是客戶端,一個(gè)TIME_WAIT狀態(tài)的連接就占用了一個(gè)本地端口。一臺(tái)機(jī)器上端口號(hào)數(shù)量的上限是65536個(gè),如果在同一臺(tái)機(jī)器上進(jìn)行壓力測(cè)試模擬上萬(wàn)的客戶請(qǐng)求,并且循環(huán)與服務(wù)端進(jìn)行短連接通信,那么這臺(tái)機(jī)器將產(chǎn)生4000個(gè)左右的TIME_WAIT Socket,后續(xù)的短連接就會(huì)產(chǎn)生address already in use : connect的異常,如果使用Nginx作為方向代理也需要考慮TIME_WAIT狀態(tài),發(fā)現(xiàn)系統(tǒng)存在大量TIME_WAIT狀態(tài)的連接,通過(guò)調(diào)整內(nèi)核參數(shù)解決。
編輯文件,加入以下內(nèi)容:
然后執(zhí)行 /in/sysctl -p 讓參數(shù)生效。
net.ipv4.tcp_syncookies = 1 表示開(kāi)啟SYN Cookies。當(dāng)出現(xiàn)SYN等待隊(duì)列溢出時(shí),啟用cookies來(lái)處理,可防范少量SYN攻擊,默認(rèn)為0,表示關(guān)閉;
net.ipv4.tcp_tw_reuse = 1 表示開(kāi)啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接,默認(rèn)為0,表示關(guān)閉;
net.ipv4.tcp_tw_recycle = 1 表示開(kāi)啟TCP連接中TIME-WAIT sockets的快速回收,默認(rèn)為0,表示關(guān)閉。
net.ipv4.tcp_fin_timeout 修改系統(tǒng)默認(rèn)的TIMEOUT時(shí)間
相關(guān)視頻推薦
10道網(wǎng)絡(luò)八股文,每道都很經(jīng)典,讓你在面試中逼格滿滿
徒手實(shí)現(xiàn)網(wǎng)絡(luò)協(xié)議棧,請(qǐng)準(zhǔn)備好環(huán)境,一起來(lái)寫代碼
學(xué)習(xí)視頻教程-騰訊課堂
需要C/C++ Linux服務(wù)器架構(gòu)師學(xué)習(xí)資料加qun獲?。ㄙY料包括
C/C++,Linux,golang技術(shù),Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒體,CDN,P2P,K8S,Docker,TCP/IP,協(xié)程,DPDK,ffmpeg
等),免費(fèi)分享
關(guān)于TCP/IP和HTTP協(xié)議的關(guān)系,網(wǎng)絡(luò)有一段比較容易理解的介紹:“我們?cè)趥鬏敂?shù)據(jù)時(shí),可以只使用(傳輸層)TCP/IP協(xié)議,但是那樣的話,如果沒(méi)有應(yīng)用層,便無(wú)法識(shí)別數(shù)據(jù)內(nèi)容。如果想要使傳輸?shù)臄?shù)據(jù)有意義,則必須使用到應(yīng)用層協(xié)議。應(yīng)用層協(xié)議有很多,比如HTTP、FTP、TELNET等,也可以自己定義應(yīng)用層協(xié)議。
HTTP協(xié)議即超文本傳送協(xié)議(Hypertext Transfer Protocol ),是Web聯(lián)網(wǎng)的基礎(chǔ),也是手機(jī)聯(lián)網(wǎng)常用的協(xié)議之一,WEB使用HTTP協(xié)議作應(yīng)用層協(xié)議,以封裝HTTP文本信息,然后使用TCP/IP做傳輸層協(xié)議將它發(fā)到網(wǎng)絡(luò)上。
由于HTTP在每次請(qǐng)求結(jié)束后都會(huì)主動(dòng)釋放連接,因此HTTP連接是一種“短連接”,要保持客戶端程序的在線狀態(tài),需要不斷地向服務(wù)器發(fā)起連接請(qǐng)求。通常 的做法是即時(shí)不需要獲得任何數(shù)據(jù),客戶端也保持每隔一段固定的時(shí)間向服務(wù)器發(fā)送一次“保持連接”的請(qǐng)求,服務(wù)器在收到該請(qǐng)求后對(duì)客戶端進(jìn)行回復(fù),表明知道 客戶端“在線”。若服務(wù)器長(zhǎng)時(shí)間無(wú)法收到客戶端的請(qǐng)求,則認(rèn)為客戶端“下線”,若客戶端長(zhǎng)時(shí)間無(wú)法收到服務(wù)器的回復(fù),則認(rèn)為網(wǎng)絡(luò)已經(jīng)斷開(kāi)。
下面是一個(gè)簡(jiǎn)單的HTTP Post application/json數(shù)據(jù)內(nèi)容的請(qǐng)求:
現(xiàn)在我們了解到TCP/IP只是一個(gè)協(xié)議棧,就像操作系統(tǒng)的運(yùn)行機(jī)制一樣,必須要具體實(shí)現(xiàn),同時(shí)還要提供對(duì)外的操作接口。就像操作系統(tǒng)會(huì)提供標(biāo)準(zhǔn)的編程接口,比如Win32編程接口一樣,TCP/IP也必須對(duì)外提供編程接口,這就是Socket?,F(xiàn)在我們知道,Socket跟TCP/IP并沒(méi)有必然的聯(lián)系。Socket編程接口在設(shè)計(jì)的時(shí)候,就希望也能適應(yīng)其他的網(wǎng)絡(luò)協(xié)議。所以,Socket的出現(xiàn)只是可以更方便的使用TCP/IP協(xié)議棧而已,其對(duì)TCP/IP進(jìn)行了抽象,形成了幾個(gè)最基本的函數(shù)接口。比如create,listen,accept,connect,read和write等等。
不同語(yǔ)言都有對(duì)應(yīng)的建立Socket服務(wù)端和客戶端的庫(kù),下面舉例Nodejs如何創(chuàng)建服務(wù)端和客戶端:
服務(wù)端:
服務(wù)監(jiān)聽(tīng)9000端口
下面使用命令行發(fā)送http請(qǐng)求和telnet
注意到curl只處理了一次報(bào)文。
客戶端
Socket長(zhǎng)連接
所謂長(zhǎng)連接,指在一個(gè)TCP連接上可以連續(xù)發(fā)送多個(gè)數(shù)據(jù)包,在TCP連接保持期間,如果沒(méi)有數(shù)據(jù)包發(fā)送,需要雙方發(fā)檢測(cè)包以維持此連接(心跳包),一般需要自己做在線維持。 短連接是指通信雙方有數(shù)據(jù)交互時(shí),就建立一個(gè)TCP連接,數(shù)據(jù)發(fā)送完成后,則斷開(kāi)此TCP連接。比如Http的,只是連接、請(qǐng)求、關(guān)閉,過(guò)程時(shí)間較短,服務(wù)器若是一段時(shí)間內(nèi)沒(méi)有收到請(qǐng)求即可關(guān)閉連接。其實(shí)長(zhǎng)連接是相對(duì)于通常的短連接而說(shuō)的,也就是長(zhǎng)時(shí)間保持客戶端與服務(wù)端的連接狀態(tài)。
通常的短連接操作步驟是:
連接 數(shù)據(jù)傳輸 關(guān)閉連接;
而長(zhǎng)連接通常就是:
連接 數(shù)據(jù)傳輸 保持連接(心跳) 數(shù)據(jù)傳輸 保持連接(心跳) …… 關(guān)閉連接;
什么時(shí)候用長(zhǎng)連接,短連接?
長(zhǎng)連接多用于操作頻繁,點(diǎn)對(duì)點(diǎn)的通訊,而且連接數(shù)不能太多情況,。每個(gè)TCP連接都需要三步握手,這需要時(shí)間,如果每個(gè)操作都是先連接,再操作的話那么處理 速度會(huì)降低很多,所以每個(gè)操作完后都不斷開(kāi),次處理時(shí)直接發(fā)送數(shù)據(jù)包就OK了,不用建立TCP連接。例如:數(shù)據(jù)庫(kù)的連接用長(zhǎng)連接, 如果用短連接頻繁的通信會(huì)造成Socket錯(cuò)誤,而且頻繁的Socket創(chuàng)建也是對(duì)資源的浪費(fèi)。
什么是心跳包為什么需要:
心跳包就是在客戶端和服務(wù)端間定時(shí)通知對(duì)方自己狀態(tài)的一個(gè)自己定義的命令字,按照一定的時(shí)間間隔發(fā)送,類似于心跳,所以叫做心跳包。網(wǎng)絡(luò)中的接收和發(fā)送數(shù)據(jù)都是使用Socket進(jìn)行實(shí)現(xiàn)。但是如果此套接字已經(jīng)斷開(kāi)(比如一方斷網(wǎng)了),那發(fā)送數(shù)據(jù)和接收數(shù)據(jù)的時(shí)候就一定會(huì)有問(wèn)題。可是如何判斷這個(gè)套接字是否還可以使用呢?這個(gè)就需要在系統(tǒng)中創(chuàng)建心跳機(jī)制。其實(shí)TCP中已經(jīng)為我們實(shí)現(xiàn)了一個(gè)叫做心跳的機(jī)制。如果你設(shè)置了心跳,那TCP就會(huì)在一定的時(shí)間(比如你設(shè)置的是3秒鐘)內(nèi)發(fā)送你設(shè)置的次數(shù)的心跳(比如說(shuō)2次),并且此信息不會(huì)影響你自己定義的協(xié)議。也可以自己定義,所謂“心跳”就是定時(shí)發(fā)送一個(gè)自定義的結(jié)構(gòu)體(心跳包或心跳幀),讓對(duì)方知道自己“在線”,以確保鏈接的有效性。
實(shí)現(xiàn):
服務(wù)端:
服務(wù)端輸出結(jié)果:
客戶端代碼:
客戶端輸出結(jié)果:
如果想要使傳輸?shù)臄?shù)據(jù)有意義,則必須使用到應(yīng)用層協(xié)議比如Http、Mqtt、Dubbo等。基于TCP協(xié)議上自定義自己的應(yīng)用層的協(xié)議需要解決的幾個(gè)問(wèn)題:
下面我們就一起來(lái)定義自己的協(xié)議,并編寫服務(wù)的和客戶端進(jìn)行調(diào)用:
定義報(bào)文頭格式: length:xxxx; xxxx代表數(shù)據(jù)的長(zhǎng)度,總長(zhǎng)度20,舉例子不嚴(yán)謹(jǐn)。
數(shù)據(jù)表的格式: Json
服務(wù)端:
日志打?。?/p>
客戶端
日志打?。?/p>
客戶端定時(shí)發(fā)送自定義協(xié)議數(shù)據(jù)到服務(wù)端,先發(fā)送頭數(shù)據(jù),在發(fā)送內(nèi)容數(shù)據(jù),另外一個(gè)定時(shí)器發(fā)送心跳數(shù)據(jù),服務(wù)端判斷是心跳數(shù)據(jù),再判斷是不是頭數(shù)據(jù),再是內(nèi)容數(shù)據(jù),然后解析后再發(fā)送數(shù)據(jù)給客戶端。從日志的打印可以看出客戶端先后writeheader和data數(shù)據(jù),服務(wù)端可能在一個(gè)data事件里面接收到。
這里可以看到一個(gè)客戶端在同一個(gè)時(shí)間內(nèi)處理一個(gè)請(qǐng)求可以很好的工作,但是想象這么一個(gè)場(chǎng)景,如果同一時(shí)間內(nèi)讓同一個(gè)客戶端去多次調(diào)用服務(wù)端請(qǐng)求,發(fā)送多次頭數(shù)據(jù)和內(nèi)容數(shù)據(jù),服務(wù)端的data事件收到的數(shù)據(jù)就很難區(qū)別哪些數(shù)據(jù)是哪次請(qǐng)求的,比如兩次頭數(shù)據(jù)同時(shí)到達(dá)服務(wù)端,服務(wù)端就會(huì)忽略其中一次,而后面的內(nèi)容數(shù)據(jù)也不一定就對(duì)應(yīng)于這個(gè)頭的。所以想復(fù)用長(zhǎng)連接并能很好的高并發(fā)處理服務(wù)端請(qǐng)求,就需要連接池這種方式了。
什么是Socket連接池,池的概念可以聯(lián)想到是一種資源的,所以Socket連接池,就是維護(hù)著一定數(shù)量Socket長(zhǎng)連接的。它能自動(dòng)檢測(cè)Socket長(zhǎng)連接的有效性,剔除無(wú)效的連接,補(bǔ)充連接池的長(zhǎng)連接的數(shù)量。從代碼層次上其實(shí)是人為實(shí)現(xiàn)這種功能的類,一般一個(gè)連接池包含下面幾個(gè)屬性:
場(chǎng)景: 一個(gè)請(qǐng)求過(guò)來(lái),首先去資源池要求獲取一個(gè)長(zhǎng)連接資源,如果空閑隊(duì)列里面有長(zhǎng)連接,就獲取到這個(gè)長(zhǎng)連接Socket,并把這個(gè)Socket移到正在運(yùn)行的長(zhǎng)連接隊(duì)列。如果空閑隊(duì)列里面沒(méi)有,且正在運(yùn)行的隊(duì)列長(zhǎng)度小于配置的連接池資源的數(shù)量,就新建一個(gè)長(zhǎng)連接到正在運(yùn)行的隊(duì)列去,如果正在運(yùn)行的不下于配置的資源池長(zhǎng)度,則這個(gè)請(qǐng)求進(jìn)入到等待隊(duì)列去。當(dāng)一個(gè)正在運(yùn)行的Socket完成了請(qǐng)求,就從正在運(yùn)行的隊(duì)列移到空閑的隊(duì)列,并觸發(fā)等待請(qǐng)求隊(duì)列去獲取空閑資源,如果有等待的情況。
這里簡(jiǎn)單介紹Nodejs的Socket連接池generic-pool模塊的源碼。
主要文件目錄結(jié)構(gòu)
下面介紹庫(kù)的使用:
初始化連接池
使用連接池
下面連接池的使用,使用的協(xié)議是我們之前自定義的協(xié)議。
日志打?。?/p>
這里看到前面兩個(gè)請(qǐng)求都建立了新的Socket連接 socket_pool 127.0.0.connect,定時(shí)器結(jié)束后重新發(fā)起兩個(gè)請(qǐng)求就沒(méi)有建立新的Socket連接了,直接從連接池里面獲取Socket連接資源。
源碼分析
發(fā)現(xiàn)主要的代碼就位于lib文件夾中的Pool.js
構(gòu)造函數(shù):
lib/Pool.js
可以看到包含之前說(shuō)的空閑的資源隊(duì)列,正在請(qǐng)求的資源隊(duì)列,正在等待的請(qǐng)求隊(duì)列等。
下面查看 Pool.acquire 方法
lib/Pool.js
上面的代碼就按種情況一直走下到最終獲取到長(zhǎng)連接的資源,其他更多代碼大家可以自己去深入了解。
關(guān)于linux心跳包c(diǎn)的介紹到此就結(jié)束了,不知道你從中找到你需要的信息了嗎 ?如果你還想了解更多這方面的信息,記得收藏關(guān)注本站。
成都創(chuàng)新互聯(lián)科技有限公司,是一家專注于互聯(lián)網(wǎng)、IDC服務(wù)、應(yīng)用軟件開(kāi)發(fā)、網(wǎng)站建設(shè)推廣的公司,為客戶提供互聯(lián)網(wǎng)基礎(chǔ)服務(wù)!
創(chuàng)新互聯(lián)(www.cdcxhl.com)提供簡(jiǎn)單好用,價(jià)格厚道的香港/美國(guó)云服務(wù)器和獨(dú)立服務(wù)器。創(chuàng)新互聯(lián)成都老牌IDC服務(wù)商,專注四川成都IDC機(jī)房服務(wù)器托管/機(jī)柜租用。為您精選優(yōu)質(zhì)idc數(shù)據(jù)中心機(jī)房租用、服務(wù)器托管、機(jī)柜租賃、大帶寬租用,可選線路電信、移動(dòng)、聯(lián)通等。
文章標(biāo)題:Linux心跳包C編程指南(linux心跳包c(diǎn))
URL網(wǎng)址:http://www.fisionsoft.com.cn/article/cojjhoe.html


咨詢
建站咨詢
