詳解PHP Swoole長(zhǎng)連接常見(jiàn)問(wèn)題_第1頁(yè)
詳解PHP Swoole長(zhǎng)連接常見(jiàn)問(wèn)題_第2頁(yè)
詳解PHP Swoole長(zhǎng)連接常見(jiàn)問(wèn)題_第3頁(yè)
詳解PHP Swoole長(zhǎng)連接常見(jiàn)問(wèn)題_第4頁(yè)
詳解PHP Swoole長(zhǎng)連接常見(jiàn)問(wèn)題_第5頁(yè)
已閱讀5頁(yè),還剩13頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

第詳解PHPSwoole長(zhǎng)連接常見(jiàn)問(wèn)題Redis可以配置如果客戶端經(jīng)過(guò)多少秒還不給Redis服務(wù)器發(fā)送數(shù)據(jù),那么就會(huì)把連接close掉。

MySQL常見(jiàn)的報(bào)錯(cuò):

配置項(xiàng):wait_timeoutinteractive_timeout

報(bào)錯(cuò)信息:

hasgoneaway

和Redis服務(wù)器一樣,MySQL也會(huì)定時(shí)的去清理掉沒(méi)用的連接。

如何解決

1、用的時(shí)候進(jìn)行重連。優(yōu)點(diǎn)是簡(jiǎn)單,缺點(diǎn)是面臨短連接的問(wèn)題。

2、定時(shí)發(fā)送心跳維持連接(推薦)。

如何維持長(zhǎng)連接

tcp協(xié)議中實(shí)現(xiàn)的tcp_keepalive

操作系統(tǒng)底層提供了一組tcp的keepalive配置:

tcp_keepalive_time(integer;default:7200;sinceLinux2.2)

ThenumberofsecondsaconnectionneedstobeidlebeforeTCP

beginssendingoutkeep-aliveprobes.Keep-alivesaresentonly

whentheSO_KEEPALIVEsocketoptionisenabled.Thedefault

valueis7200seconds(2hours).Anidleconnectionis

terminatedafterapproximatelyanadditional11minutes(9

probesanintervalof75secondsapart)whenkeep-aliveis

enabled.

Notethatunderlyingconnectiontrackingmechanismsand

applicationtimeoutsmaybemuchshorter.

tcp_keepalive_intvl(integer;default:75;sinceLinux2.4)

ThenumberofsecondsbetweenTCPkeep-aliveprobes.

tcp_keepalive_probes(integer;default:9;sinceLinux2.2)

ThemaximumnumberofTCPkeep-aliveprobestosendbefore

givingupandkillingtheconnectionifnoresponseisobtained

fromtheotherend.

8

Swoole底層把這些配置開(kāi)放出來(lái)了,例如:

$server=new\Swoole\Server('127.0.0.1',6666,SWOOLE_PROCESS);

$server-set([

'worker_num'=1,

'open_tcp_keepalive'=1,

'tcp_keepidle'=4,//對(duì)應(yīng)tcp_keepalive_time

'tcp_keepinterval'=1,//對(duì)應(yīng)tcp_keepalive_intvl

'tcp_keepcount'=5,//對(duì)應(yīng)tcp_keepalive_probes

]);

其中:

'open_tcp_keepalive'=1,//總開(kāi)關(guān),用來(lái)開(kāi)啟tcp_keepalive

'tcp_keepidle'=4,//4s沒(méi)有數(shù)據(jù)傳輸就進(jìn)行檢測(cè)

//檢測(cè)的策略如下:

'tcp_keepinterval'=1,//1s探測(cè)一次,即每隔1s給客戶端發(fā)一個(gè)包(然后客戶端可能會(huì)回一個(gè)ack的包,如果服務(wù)端收到了這個(gè)ack包,那么說(shuō)明這個(gè)連接是活著的)

'tcp_keepcount'=5,//探測(cè)的次數(shù),超過(guò)5次后客戶端還沒(méi)有回ack包,那么close此連接

我們來(lái)實(shí)戰(zhàn)測(cè)試體驗(yàn)一下,服務(wù)端腳本如下:

$server=new\Swoole\Server('127.0.0.1',6666,SWOOLE_PROCESS);

$server-set([

'worker_num'=1,

'open_tcp_keepalive'=1,//開(kāi)啟tcp_keepalive

'tcp_keepidle'=4,//4s沒(méi)有數(shù)據(jù)傳輸就進(jìn)行檢測(cè)

'tcp_keepinterval'=1,//1s探測(cè)一次

'tcp_keepcount'=5,//探測(cè)的次數(shù),超過(guò)5次后還沒(méi)有回包c(diǎn)lose此連接

$server-on('connect',function($server,$fd){

var_dump("Client:Connect$fd");

$server-on('receive',function($server,$fd,$reactor_id,$data){

var_dump($data);

$server-on('close',function($server,$fd){

var_dump("closefd$fd");

$server-start();

我們啟動(dòng)這個(gè)服務(wù)器:

~/codeDir/phpCode/hyperf-skeleton#phpserver.php

然后通過(guò)tcpdump進(jìn)行抓包:

~/codeDir/phpCode/hyperf-skeleton#tcpdump-iloport6666

tcpdump:verboseoutputsuppressed,use-vor-vvforfullprotocoldecode

listeningonlo,link-typeEN10MB(Ethernet),capturesize262144bytes

我們此時(shí)正在監(jiān)聽(tīng)lo上的6666端口的數(shù)據(jù)包。

然后我們用客戶端去連接它:

~/codeDir/phpCode/hyperf-skeleton#nc127.0.0.16666

此時(shí)服務(wù)端會(huì)打印出消息:

~/codeDir/phpCode/hyperf-skeleton#phpserver.php

string(17)"Client:Connect1"

tcpdump的輸出信息如下:

01:48:40.178439IPlocalhost.33933localhost.6666:Flags[S],seq43162537,win43690,options[mss65495,sackOK,TSval9833698ecr0,nop,wscale7],length0

01:48:40.178484IPlocalhost.6666localhost.33933:Flags[S.],seq1327460565,ack43162538,win43690,options[mss65495,sackOK,TSval9833698ecr9833698,nop,wscale7],length0

01:48:40.178519IPlocalhost.33933localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval9833698ecr9833698],length0

01:48:44.229926IPlocalhost.6666localhost.33933:Flags[.],ack1,win342,options[nop,nop,TSval9834104ecr9833698],length0

01:48:44.229951IPlocalhost.33933localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval9834104ecr9833698],length0

01:48:44.229926IPlocalhost.6666localhost.33933:Flags[.],ack1,win342,options[nop,nop,TSval9834104ecr9833698],length0

01:48:44.229951IPlocalhost.33933localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval9834104ecr9833698],length0

01:48:44.229926IPlocalhost.6666localhost.33933:Flags[.],ack1,win342,options[nop,nop,TSval9834104ecr9833698],length0

//省略了其他的輸出

我們會(huì)發(fā)現(xiàn)最開(kāi)始的時(shí)候,會(huì)打印三次握手的包:

01:48:40.178439IPlocalhost.33933localhost.6666:Flags[S],seq43162537,win43690,options[mss65495,sackOK,TSval9833698ecr0,nop,wscale7],length0

01:48:40.178484IPlocalhost.6666localhost.33933:Flags[S.],seq1327460565,ack43162538,win43690,options[mss65495,sackOK,TSval9833698ecr9833698,nop,wscale7],length0

01:48:40.178519IPlocalhost.33933localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval9833698ecr9833698],length0

然后,停留了4s沒(méi)有任何包的輸出。

之后,每隔1s左右就會(huì)打印出一組:

01:52:54.359341IPlocalhost.6666localhost.43101:Flags[.],ack1,win342,options[nop,nop,TSval9859144ecr9858736],length0

01:52:54.359377IPlocalhost.43101localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval9859144ecr9855887],length0

其實(shí)這就是我們配置的策略:

'tcp_keepinterval'=1,//1s探測(cè)一次

'tcp_keepcount'=5,//探測(cè)的次數(shù),超過(guò)5次后還沒(méi)有回包c(diǎn)lose此連接

因?yàn)槲覀儾僮飨到y(tǒng)底層會(huì)自動(dòng)的給客戶端回ack,所以這個(gè)連接不會(huì)在5次探測(cè)后被關(guān)閉。操作系統(tǒng)底層會(huì)持續(xù)不斷的發(fā)送這樣的一組包:

01:52:54.359341IPlocalhost.6666localhost.43101:Flags[.],ack1,win342,options[nop,nop,TSval9859144ecr9858736],length0

01:52:54.359377IPlocalhost.43101localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval9859144ecr9855887],length0

如果我們要測(cè)試5次探測(cè)后關(guān)閉這個(gè)連接,可以禁掉6666端口的包:

~/codeDir/phpCode/hyperf-skeleton#iptables-AINPUT-ptcp--dport6666-jDROP

這樣會(huì)把所有從6666端口進(jìn)來(lái)的包給禁掉,自然,服務(wù)器就接收不到從客戶端那一邊發(fā)來(lái)的ack包了。

然后服務(wù)器過(guò)5秒就會(huì)打印出close(服務(wù)端主動(dòng)的調(diào)用了close方法,給客戶端發(fā)送了FIN包):

~/codeDir/phpCode/hyperf-skeleton#phpserver.php

string(17)"Client:Connect1"

string(10)"closefd1"

我們恢復(fù)一下iptables的規(guī)則:

~/codeDir/phpCode#iptables-DINPUT-ptcp-mtcp--dport6666-jDROP

即把我們?cè)O(shè)置的規(guī)則給刪除了。

通過(guò)tcp_keepalive的方式實(shí)現(xiàn)心跳的功能,優(yōu)點(diǎn)是簡(jiǎn)單,不要寫(xiě)代碼就可以完成這個(gè)功能,并且發(fā)送的心跳包小。缺點(diǎn)是依賴于系統(tǒng)的網(wǎng)絡(luò)環(huán)境,必須保證服務(wù)器和客戶端都實(shí)現(xiàn)了這樣的功能,需要客戶端配合發(fā)心跳包。還有一個(gè)更為嚴(yán)重的缺點(diǎn)是如果客戶端和服務(wù)器不是直連的,而是通過(guò)代理來(lái)進(jìn)行連接的,例如socks5代理,它只會(huì)轉(zhuǎn)發(fā)應(yīng)用層的包,不會(huì)轉(zhuǎn)發(fā)更為底層的tcp探測(cè)包,那這個(gè)心跳功能就失效了。

所以,Swoole就提供了其他的解決方案,一組檢測(cè)死連接的配置。

'heartbeat_check_interval'=1,//1s探測(cè)一次

'heartbeat_idle_time'=5,//5s未發(fā)送數(shù)據(jù)包就close此連接

swoole實(shí)現(xiàn)的heartbeat

我們來(lái)測(cè)試一下:

$server=new\Swoole\Server('127.0.0.1',6666,SWOOLE_PROCESS);

$server-set([

'worker_num'=1,

'heartbeat_check_interval'=1,//1s探測(cè)一次

'heartbeat_idle_time'=5,//5s未發(fā)送數(shù)據(jù)包就close此連接

$server-on('connect',function($server,$fd){

var_dump("Client:Connect$fd");

$server-on('receive',function($server,$fd,$reactor_id,$data){

var_dump($data);

$server-on('close',function($server,$fd){

var_dump("closefd$fd");

$server-start();

然后啟動(dòng)服務(wù)器:

~/codeDir/phpCode/hyperf-skeleton#phpserver.php

然后啟動(dòng)tcpdump:

~/codeDir/phpCode#tcpdump-iloport6666

tcpdump:verboseoutputsuppressed,use-vor-vvforfullprotocoldecode

listeningonlo,link-typeEN10MB(Ethernet),capturesize262144bytes

然后再啟動(dòng)客戶端:

~/codeDir/phpCode/hyperf-skeleton#nc127.0.0.16666

此時(shí)服務(wù)器端打印:

~/codeDir/phpCode/hyperf-skeleton#phpserver.php

string(17)"Client:Connect1"

然后tcpdump打?。?/p>

02:48:32.516093IPlocalhost.42123localhost.6666:Flags[S],seq1088388248,win43690,options[mss65495,sackOK,TSval10193342ecr0,nop,wscale7],length0

02:48:32.516133IPlocalhost.6666localhost.42123:Flags[S.],seq80508236,ack1088388249,win43690,options[mss65495,sackOK,TSval10193342ecr10193342,nop,wscale7],length0

02:48:32.516156IPlocalhost.42123localhost.6666:Flags[.],ack1,win342,options[nop,nop,TSval10193342ecr10193342],length0

這是三次握手信息。

然后過(guò)了5s后,tcpdump會(huì)打印出:

02:48:36.985027IPlocalhost.6666localhost.42123:Flags[F.],seq1,ack1,win342,options[nop,nop,TSval10193789ecr10193342],length0

02:48:36.992172IPlocalhost.42123localhost.6666:Flags[.],ack2,win342,options[nop,nop,TSval10193790ecr10193789],length0

也就是服務(wù)端發(fā)送了FIN包。因?yàn)榭蛻舳藳](méi)有發(fā)送數(shù)據(jù),所以Swoole關(guān)閉了連接。

然后服務(wù)器端會(huì)打印:

~/codeDir/phpCode/hyperf-skeleton#phpserver.php

string(17)"Client:Connect1"

string(10)"closefd1"

所以,heartbeat和tcpkeepalive還是有一定的區(qū)別的,tcpkeepalive有?;钸B接的功能,但是heartbeat存粹是檢測(cè)沒(méi)有數(shù)據(jù)的連接,然后關(guān)閉它,并且只可以在服務(wù)端這邊配置,如果需要保活,也可以讓客戶端配合發(fā)送心跳。

如果我們不想讓服務(wù)端close掉連接,那么就得在應(yīng)用層里面不斷的發(fā)送數(shù)據(jù)包來(lái)進(jìn)行保活,例如我在nc客戶端里面不斷的發(fā)送包:

~/codeDir/phpCode/hyperf-skeleton#nc127.0.0.16666

ping

ping

ping

ping

ping

ping

ping

ping

ping

我發(fā)送了9個(gè)ping包給服務(wù)器,tcpdump的輸出如下:

//省略了三次握手的包

02:57:53.697363IPlocalhost.44195localhost.6666:Flags[P.],seq1:6,ack1,win342,options[nop,nop,TSval10249525ecr10249307],length5

02:57:53.697390IPlocalhost.6666localhost.44195:Flags[.],ack6,win342,options[nop,nop,TSval10249525ecr10249525],length0

02:57:55.309532IPlocalhost.44195localhost.6666:Flags[P.],seq6:11,ack1,win342,options[nop,nop,TSval10249686ecr10249525],length5

02:57:55.309576IPlocalhost.6666localhost.44195:Flags[.],ack11,win342,options[nop,nop,TSval10249686ecr10249686],length0

02:57:58.395206IPlocalhost.44195localhost.6666:Flags[P.],seq11:16,ack1,win342,options[nop,nop,TSval10249994ecr10249686],length5

02:57:58.395239IPlocalhost.6666localhost.44195:Flags[.],ack16,win342,options[nop,nop,TSval10249994ecr10249994],length0

02:58:01.858094IPlocalhost.44195localhost.6666:Flags[P.],seq16:21,ack1,win342,options[nop,nop,TSval10250341ecr10249994],length5

02:58:01.858126IPlocalhost.6666localhost.44195:Flags[.],ack21,win342,options[nop,nop,TSval10250341ecr10250341],length0

02:58:04.132584IPlocalhost.44195localhost.6666:Flags[P.],seq21:26,ack1,win342,options[nop,nop,TSval10250568ecr10250341],length5

02:58:04.132609IPlocalhost.6666localhost.44195:Flags[.],ack26,win342,options[nop,nop,TSval10250568ecr10250568],length0

02:58:05.895704IPlocalhost.44195localhost.6666:Flags[P.],seq26:31,ack1,win342,options[nop,nop,TSval10250744ecr10250568],length5

02:58:05.895728IPlocalhost.6666localhost.44195:Flags[.],ack31,win342,options[nop,nop,TSval10250744ecr10250744],length0

02:58:07.150265IPlocalhost.44195localhost.6666:Flags[P.],seq31:36,ack1,win342,options[nop,nop,TSval10250870ecr10250744],length5

02:58:07.150288IPlocalhost.6666localhost.44195:Flags[.],ack36,win342,options[nop,nop,TSval10250870ecr10250870],length0

02:58:08.349124IPlocalhost.44195localhost.6666:Flags[P.],seq36:41,ack1,win342,options[nop,nop,TSval10250990ecr10250870],length5

02:58:08.349156IPlocalhost.6666localhost.44195:Flags[.],ack41,win342,options[nop,nop,TSval10250990ecr10250990],length0

02:58:09.906223IPlocalhost.44195localhost.6666:Flags[P.],seq41:46,ack1,win342,options[nop,nop,TSval10251145ecr10250990],length5

02:58:09.906247IPlocalhost.6666localhost.44195:Flags[.],ack46,win342,options[nop,nop,TSval10251145ecr10251145],length0

有9組數(shù)據(jù)包的發(fā)送。(這里的Flags[P.]代表Push的含義)

此時(shí)服務(wù)器還沒(méi)有close掉連接,實(shí)現(xiàn)了客戶端?;钸B接的功能。然后我們停止發(fā)送ping,過(guò)了5秒后tcpdump就會(huì)輸出一組:

02:58:14.811761IPlocalhost.6666localhost.44195:Flags[F.],seq1,ack46,win342,options[nop,nop,TSval10251636ecr10251145],length0

02:58:14.816420IPlocalhost.44195localhost.6666:Flags[.],ack2,win342,options[nop,nop,TSval10251637ecr10251636],length0

服務(wù)端那邊發(fā)送了FIN包,說(shuō)明服務(wù)端close掉了連接。服務(wù)端的輸出如下:

~/codeDir/phpCode/hyperf-sk

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論