鍍金池/ 問答/PHP  C++/ php調(diào)用stream_get_contents從tcp套接字中獲取數(shù)據(jù),有時能

php調(diào)用stream_get_contents從tcp套接字中獲取數(shù)據(jù),有時能夠調(diào)用一次就能獲取全部,有時獲取為空需要循環(huán)查詢

<?php

$socket = stream_socket_server('tcp://127.0.0.1:8888',$errno,$errstr,STREAM_SERVER_BIND|STREAM_SERVER_LISTEN);
if(!$socket){

die('failed to create a socket');

}
stream_set_blocking($socket,false);
//監(jiān)聽新連接
$ev = new EvIo($socket,Ev::READ,function ($watcher) use($socket,$clients){

$client = stream_socket_accept($socket);
stream_set_blocking($client,false);
//監(jiān)聽客戶端信息
$e = new EvIo($client,Ev::READ|Ev::WRITE,function ($watcher) use($client){
    $data = stream_get_contents($client);
    echo $data;//有時輸出為空,有時完整輸出
    /* do{
        $data = stream_get_contents($client);
    }while($data==false);
    發(fā)現(xiàn)有時一次就能獲取,有時需要重復調(diào)用知道獲取到
    */
    fclose($client);
    $watcher->stop();
});
Ev::run();

});
Ev::run();

請問是什么原因造成的

回答
編輯回答
笨尐豬

你要知道TCP是流式協(xié)議,沒有消息邊界的,UDP是有消息邊界的,所以你發(fā)送端的數(shù)據(jù),到接收端這邊,可能需要一次,或者兩次,或者一次把兩次發(fā)送的數(shù)據(jù)都接收了
610439-20160528150523303-1600111497.png
你可以想象你是在接收水流,所以你是不知道它那里結束的
可以搜索TCP粘包問題,一般解決方案有:

  • 發(fā)送定長包。如果每個消息的大小都是一樣的,那么在接收對等方只要累計接收數(shù)據(jù),直到數(shù)據(jù)等于一個定長的數(shù)值就將它作為一個消息。
  • 包尾加上rn標記。FTP協(xié)議正是這么做的。但問題在于如果數(shù)據(jù)正文中也含有rn,則會誤判為消息的邊界。
  • 包頭加上包體長度。包頭是定長的4個字節(jié),說明了包體的長度。接收對等方先接收包體長度,依據(jù)包體長度來接收包體。
  • 使用更加復雜的應用層協(xié)議。
2017年1月3日 22:28