workerman當(dāng)然是完整的沒(méi)有粘包問(wèn)題,但是我使用自己的程序接收workerman發(fā)送過(guò)來(lái)的信息時(shí)出現(xiàn)了這個(gè)問(wèn)題,即從workerman發(fā)送的一條一條的信息變成了一整條的了,這個(gè)有一個(gè)通用的解決方案嗎,我使用的是文本傳遞協(xié)議。。。求解
使用接收程序如下:
while ( $buf = stream_socket_recvfrom ( $new_conn, 65535 ) ) {
$all_buffer .= $buf;
if($buf === "\n") {
break;
}
return $all_buffer;
}
接收一個(gè)一個(gè)字符接收是為了檢查邊界
結(jié)果很明顯會(huì)有粘包的現(xiàn)象,因?yàn)橐幌伦幼x那么多,而且接收的數(shù)據(jù)實(shí)際是上多條的,
在這里判斷邊界其實(shí)是沒(méi)有意義的,那么怎么辦呢:
while ( $buf = stream_socket_recvfrom ( $new_conn, 1 ) ) {
$all_buffer .= $buf;
if($buf == "\n") {
break;
}
return $all_buffer;
}
我就一個(gè)一個(gè)的接收,這總行了吧,結(jié)果又是沒(méi)什么:
沒(méi)有了粘包問(wèn)題,但接收的數(shù)據(jù)把我的整條信息拆開(kāi)了,這又不是我想要的,為什么會(huì)在接收到 "\n"之前我的循環(huán)就跳出了呢?
這得考慮socket數(shù)據(jù)傳輸?shù)奶匦粤耍@的規(guī)則是我們接收和發(fā)送定義的,而它自己的規(guī)則對(duì)我們來(lái)說(shuō)沒(méi)有實(shí)際的處理意義,即stream_socket_recvfrom返回來(lái)的可能為空。沒(méi)能等到"\n"就已經(jīng)跳出了。
最后walkor提供了以下方法:
$all_buffer = '';
while(1)
{
$buf = stream_socket_recvfrom ( $new_conn, 1 );
if(empty($buf))
{
if(feof($buf))
{
break;
}
continue;
}
$all_buffer .= $buf;
if($buf == "\n")
{
break;
}
}
return $all_buffer;
問(wèn)題解決。
處理方法類(lèi)似,根據(jù)協(xié)議判斷請(qǐng)求邊界。
例如協(xié)議是 json+回車(chē)
客戶端應(yīng)該類(lèi)似這樣讀
$client = stream_socket_client('tcp://ip:port');
$all_buffer = '';
while(1)
{
// 每次讀一個(gè)字節(jié),因?yàn)槊總€(gè)字節(jié)都有可能是代表數(shù)據(jù)的結(jié)束的回車(chē)字符
$buf = stream_socket_recvfrom($client, 1);
// stream_socket_recvfrom 可能返回空,比如$client是非阻塞的,或者被信號(hào)打斷、斷開(kāi)、超時(shí)等
if(empty($buf) && $buf != '0')
{
// 鏈接斷開(kāi)就跳出
if(feof($buf))
{
break;
}
// 繼續(xù)
continue;
}
// 拼接數(shù)據(jù)
$all_buffer .= $buf;
// 是請(qǐng)求邊界就跳出
if($buf == "\n")
{
break;
}
}
當(dāng)然上面的協(xié)議簡(jiǎn)單,但是由于是一個(gè)字節(jié)一個(gè)字節(jié)的讀,對(duì)性能有一點(diǎn)點(diǎn)的損耗
如果對(duì)性能要求非常非??量?,可以采用 類(lèi)似 包長(zhǎng)+包體 的協(xié)議傳輸
看了一下代碼。是不是
if(empty($buf))
{
// 鏈接斷開(kāi)就跳出
if(feof($buf))
{
break;
}
// 繼續(xù)
continue;
}
這樣就把字符中的空格給抹掉了?