這篇文章主要講解了“php socket編程中客戶端異常關(guān)閉導(dǎo)致服務(wù)端中斷的問(wèn)題怎么解決”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來(lái)研究和學(xué)習(xí)“php socket編程中客戶端異常關(guān)閉導(dǎo)致服務(wù)端中斷的問(wèn)題怎么解決”吧!

創(chuàng)新互聯(lián)建站的客戶來(lái)自各行各業(yè),為了共同目標(biāo),我們?cè)诠ぷ魃厦芮信浜希瑥膭?chuàng)業(yè)型小企業(yè)到企事業(yè)單位,感謝他們對(duì)我們的要求,感謝他們從不同領(lǐng)域給我們帶來(lái)的挑戰(zhàn),讓我們激情的團(tuán)隊(duì)有機(jī)會(huì)用頭腦與智慧不斷的給客戶帶來(lái)驚喜。專業(yè)領(lǐng)域包括網(wǎng)站建設(shè)、成都做網(wǎng)站、電商網(wǎng)站開(kāi)發(fā)、微信營(yíng)銷、系統(tǒng)平臺(tái)開(kāi)發(fā)。
原因如下:
1.socket_recv支持多種flag,用于不同場(chǎng)景
2.socket_recv可以檢測(cè)socket關(guān)閉的情況(例如對(duì)端關(guān)閉了socket)
返回值:$return_value=socket_recv(...)
含義: >0 表示接收到的字節(jié)數(shù);
===0, 發(fā)生了錯(cuò)誤,socket closed;
===false,無(wú)數(shù)據(jù),socket not closed。
socket_read不能判斷socket是否已經(jīng)斷開(kāi)。
測(cè)試流程:
啟動(dòng)server端,再啟動(dòng)client端:可以正常通信。
kill掉client端,結(jié)果server端只能讀取到空字符串。
測(cè)試代碼如下:
file: bug1_server.php
<?php
/**
* file: bug1_server.php
* socket server
* 基于php socket函數(shù)族
* IO模型:同步阻塞
* 粘包處理:固定長(zhǎng)度
* 連接數(shù):1個(gè)socket連接
*
* 測(cè)試目標(biāo):模擬client crash時(shí),server無(wú)法判斷socket是否斷開(kāi)
* 測(cè)試結(jié)果:kill殺掉client進(jìn)程后,server進(jìn)程socket_last_error()返回為0,無(wú)法判斷socket是否關(guān)閉
*
* @author davidyanxw
* @date 2018.04.27
*/
set_time_limit(0);
//創(chuàng)建服務(wù)端的socket套接流,net協(xié)議為IPv4,protocol協(xié)議為TCP
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// reuse address
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
/*綁定接收的套接流主機(jī)和端口,與客戶端相對(duì)應(yīng)*/
if (socket_bind($socket, '127.0.0.1', 8801) == false) {
echo 'server bind fail:' . socket_strerror(socket_last_error());
}
//監(jiān)聽(tīng)套接流
if (socket_listen($socket, 4) == false) {
echo 'server listen fail:' . socket_strerror(socket_last_error());
}
$accept_resource = socket_accept($socket);
if($accept_resource === false) {
echo "accept connection failed".PHP_EOL;
exit;
}
// 讀寫(xiě)超時(shí)時(shí)間:0.8s
socket_set_option($accept_resource, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 0, "usec" => 800000));
socket_set_option($accept_resource, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 0, "usec" => 800000));
// stream固定長(zhǎng)度
$len = 100;
//讓服務(wù)器不停獲取客戶端傳過(guò)來(lái)的信息
while (true) {
$string_read = socket_read($accept_resource, $len);
if($string_read === false) {
echo "socket error:" . socket_last_error() . ",error msg:" . socket_strerror(socket_last_error()) . PHP_EOL;
break;
}
elseif($string_read == '') {
if(in_array(socket_last_error(), [SOCKET_EPIPE, SOCKET_ECONNRESET])) {
echo "socket error:".socket_last_error().",error msg:".socket_strerror(socket_last_error()).PHP_EOL;
break;
}
if(in_array(socket_last_error(), [SOCKET_EAGAIN])) {
// EAGAIN, retry later
usleep(500);
continue;
}
echo "server receive empty:" . socket_last_error() . ",error msg:" . socket_strerror(socket_last_error()) . PHP_EOL;
}
else {
$string = trim($string_read);
echo 'server receive success,msg:['.$string.'],time:' . microtime(true) . PHP_EOL;
}
} ;
// 先shutdown,后close
@socket_shutdown($accept_resource);
socket_close($accept_resource);
@socket_shutdown($socket);
socket_close($socket);
/**
* 生成php隨機(jī)串
* @param $length
* @return string
*/
function randomkeys($length){
$output='';
for ($a = 0; $a<$length; $a++) {
$output .= chr(mt_rand(33, 126));
}
return $output;
}
?>file:bug1_client.php
<?php
/**
* file:bug1_client.php
* socket client
* 基于php socket函數(shù)族
* IO模型:同步阻塞
* 粘包處理:固定長(zhǎng)度
* 連接數(shù):1個(gè)socket連接
*
* @author davidyanxw
* @date 2018.04.27
*/
set_time_limit(0);
//創(chuàng)建一個(gè)socket套接流
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
//接收套接流的最大超時(shí)時(shí)間(800ms)
//發(fā)送套接流的最大超時(shí)時(shí)間(800ms)
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 0, "usec" => 800000));
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 0, "usec" => 800000));
$len = 100;
//連接服務(wù)端的套接流,這一步就是使客戶端與服務(wù)器端的套接流建立聯(lián)系
if (socket_connect($socket, '127.0.0.1', 8801) == false) {
echo 'connect fail massege:' . socket_strerror(socket_last_error());
} else {
while(1){
$ori_msg = 'Hello, server!'.randomkeys(8);
$message_write = str_pad($ori_msg, $len);
//向服務(wù)端寫(xiě)入字符串信息
$sent = @socket_write($socket, $message_write, $len);
if ($sent === false) {
if(in_array(socket_last_error(), [SOCKET_EPIPE, SOCKET_ECONNRESET])) {
echo "socket error:".socket_last_error().",error msg:".socket_strerror(socket_last_error()).PHP_EOL;
break;
}
echo "socket error:".socket_last_error().",error msg:".socket_strerror(socket_last_error()).PHP_EOL;
}
else{
echo 'client write success,msg:['.$ori_msg.'],time:' . microtime(true).PHP_EOL;
}
// break;
}
}
@socket_shutdown($socket);
socket_close($socket);
/**
* 生成php隨機(jī)串
* @param $length
* @return string
*/
function randomkeys($length){
$output='';
for ($a = 0; $a<$length; $a++) {
$output .= chr(mt_rand(33, 126));
}
return $output;
}
?>正確的代碼是:(file: debug1_server.php)
<?php
/**
* file: debug1_server.php
* socket server
* 基于php socket函數(shù)族
* IO模型:同步阻塞
* 粘包處理:固定長(zhǎng)度
* 連接數(shù):1個(gè)socket連接
*
* 測(cè)試目標(biāo):模擬client crash時(shí),server無(wú)法判斷socket是否斷開(kāi)
* 測(cè)試結(jié)果:kill殺掉client進(jìn)程后,server進(jìn)程socket_last_error()返回為0,無(wú)法判斷socket是否關(guān)閉
*
* @author davidyanxw
* @date 2018.04.27
*/
set_time_limit(0);
//創(chuàng)建服務(wù)端的socket套接流,net協(xié)議為IPv4,protocol協(xié)議為TCP
$socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP);
// reuse address
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
/*綁定接收的套接流主機(jī)和端口,與客戶端相對(duì)應(yīng)*/
if (socket_bind($socket, '127.0.0.1', 8801) == false) {
echo 'server bind fail:' . socket_strerror(socket_last_error());
}
//監(jiān)聽(tīng)套接流
if (socket_listen($socket, 4) == false) {
echo 'server listen fail:' . socket_strerror(socket_last_error());
}
$accept_resource = socket_accept($socket);
if($accept_resource === false) {
echo "accept connection failed".PHP_EOL;
exit;
}
// 讀寫(xiě)超時(shí)時(shí)間:0.8s
socket_set_option($accept_resource, SOL_SOCKET, SO_RCVTIMEO, array("sec" => 0, "usec" => 800000));
socket_set_option($accept_resource, SOL_SOCKET, SO_SNDTIMEO, array("sec" => 0, "usec" => 800000));
// stream固定長(zhǎng)度
$len = 100;
//讓服務(wù)器不停獲取客戶端傳過(guò)來(lái)的信息
while (true) {
/* 使用socket_recv */
$len_read = socket_recv($accept_resource, $string_read, $len, 0);
if ($len_read === false) {
// no data
echo "no data".PHP_EOL;
continue;
}
elseif($len_read === 0 ) {
// socket closed
echo "socket error:" . socket_last_error() . ",error msg:" . socket_strerror(socket_last_error()) . PHP_EOL;
break;
}
else {
$string = trim($string_read);
echo 'server receive success,msg:['.$string.'],time:' . microtime(true) . PHP_EOL;
}
} ;
// 先shutdown,后close
@socket_shutdown($accept_resource);
socket_close($accept_resource);
@socket_shutdown($socket);
socket_close($socket);
/**
* 生成php隨機(jī)串
* @param $length
* @return string
*/
function randomkeys($length){
$output='';
for ($a = 0; $a<$length; $a++) {
$output .= chr(mt_rand(33, 126));
}
return $output;
}
?>感謝各位的閱讀,以上就是“php socket編程中客戶端異常關(guān)閉導(dǎo)致服務(wù)端中斷的問(wèn)題怎么解決”的內(nèi)容了,經(jīng)過(guò)本文的學(xué)習(xí)后,相信大家對(duì)php socket編程中客戶端異常關(guān)閉導(dǎo)致服務(wù)端中斷的問(wèn)題怎么解決這一問(wèn)題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是創(chuàng)新互聯(lián),小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!
本文標(biāo)題:phpsocket編程中客戶端異常關(guān)閉導(dǎo)致服務(wù)端中斷的問(wèn)題怎么解決
地址分享:http://www.chinadenli.net/article0/ipheio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供搜索引擎優(yōu)化、網(wǎng)站內(nèi)鏈、微信小程序、關(guān)鍵詞優(yōu)化、用戶體驗(yàn)、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)