私は 2 つのソケット クライアントを並べて実行し、http ストリーミング データを収集しています (Twitter ではなく、似たようなものです)。データはチャンク エンコーディングで送信されます。
クライアントの 1 つは curl (php-curl ではなくコマンドライン) で、http と https の両方が正常に機能します。fsockopen
もう 1 つは、 と を使用した独自の PHP スクリプトfgets
です。https では正常に動作しますが、http には特定の問題があります。どのように具体的ですか?ストリームが 60 秒間静かになった場合にのみ発生します。静かな時間が 50 秒しかない場合は、正常に動作します。自分のスクリプトで送受信された curl の http ヘッダーを比較して、すべての違いを取り除きました。PHP ソケット、特にチャンク エンコーディングについて知っておくべきことはすべて知っていると思っていましたが、これには困惑したので、謙虚なパイを食べる時が来ました。
そのため、「--trace - --trace-time」を指定して curl を実行すると、60 秒間の休止期間の後に最初のパケットが通過することがわかります。
05:56:57.025023 <= Recv data, 136 bytes (0x88)
0000: 38 32 0d 0a 7b 22 64 61 74 61 66 65 65 64 22 3a 82..{"datafeed":
0010: 22 64 65 6d 6f 2e 31 64 36 2e 31 6d 2e 72 61 6e "demo.1d6.1m.ran
...
0080: 34 22 7d 5d 7d 0a 0d 0a 4"}]}...
82 は、チャンクのサイズを表す 16 進数です。\r\n は、チャンク サイズの行の終わりを示します。チャンクは「{」から始まります。
PHP 側では、私のループは次のように始まります。
while(true){
if(feof($fp)){fclose($fp);return "Remote server has closed\n";}
$chunk_info=trim(fgets($fp)); //First line is hex digits giving us the length
$len=hexdec($chunk_info); //$len includes the \r\n at the end of the chunk (despite what wikipedia says)
https を使用する場合、または 60 秒未満のギャップがある場合、これは正常に機能します。$len は 100 またはチャンク サイズが何であれです。しかし、その 60 秒のギャップの後、$chunk_info には次のように表示されます。
datafeed":"demo.1d6.1m.ran...
したがって、最初の 6 バイトが失われたようです。38 32 0d 0a 7b 22
後続のすべてのチャンクは問題なく、curl が受け取るものとまったく同じです。
バージョンの詳細
curl 7.19.7 (x86_64-pc-linux-gnu) libcurl/7.19.7 OpenSSL/0.9.8k zlib/1.2.3.3 libidn/1.15 プロトコル: tftp ftp telnet dict ldap ldaps http file https ftps 機能: GSS ネゴシエート IDN IPv6 Largefile NTLM SSL libz
PHP 5.3.2-1ubuntu4.18 with Suhosin-Patch (cli) (ビルド: 2012 年 9 月 12 日 19:12:47)
サーバー: Apache/2.2.14 (Ubuntu)
(これまでのところ、ローカルホスト接続でのみテストしました。)
残りのループは次のようになります。
$s='';
$len+=2; //For the \r\n at the end of the chunk
while(!feof($fp)){
$s.=fread($fp,$len-strlen($s));
if(strlen($s)>=$len)break; //TODO: Can never be >$len, only ==$len??
}
$s=substr($s,0,-2);
if(!$s)continue;
$d=json_decode($s);
//Do something with $d here
}
(余談: これまでにテストした方法では、コードは 60 秒間の休止期間の前に、このループを 1 回だけ通過しました。)
注: 機能させるための回避策は多数あります。たとえば、https の使用を強制するか、curl-php を使用します。この質問は、何が起こっているのか、60 秒後に何が変化しているのか、そしてそれを止める方法を知りたいからです。また、新しいトラブルシューティングのアイデアを学ぶこともできます。血まみれの知的好奇心と考えてください:-)