在PHP中作为客户端与服务器端使用socket进行通信时,一般我们使用fsockopen,但在使用这个函数进行通信时,有时候发现数据的反应时间特别长,更有甚者能达到1分钟。以下是代码片段:
1 <?php 2 3 function send($data /* String */) { 4 $result = ''; 5 6 $fp = fsockopen($this->url, $this->port, $errno, $errstr, 10); 7 8 if (!$fp) { 9 return null; 10 } else { 11 fputs($fp, $this->method." ".$this->uri." HTTP/1.1\r\n"); 12 fputs($fp, "Host: ".$this->url.":".$this->port."\r\n"); 13 fputs($fp, "Content-type: text/html;charset=".$this->charset."\r\n"); 14 fputs($fp, "Accept-Language: zh-cn\r\n"); 15 fputs($fp, "User-Agent: Mozilla/4.0(Compatible win32; MSIE)\r\n"); 16 fputs($fp, "Content-Length: ".strlen($data)."\r\n"); 17 fputs($fp, "Connection: close\r\n\r\n"); 18 fputs($fp, $data); 19 20 while(!feof($fp)) { 21 $result .= fgets($fp, 1024); 22 } 23 24 fclose($fp); 25 26 $arr = split("\r\n", $result); 27 $state = split(" ", $arr[0]); 28 29 if (substr($state[1], 0, 1) != 2) { 30 return null; 31 } else { 32 return substr($result, strpos($result, "\r\n\r\n") + 4); 33 } 34 } 35 }
上面这段代码就会有时候出现数据响应时间特别长。经过调试发现问题出在fgets这个函数的返回上,最后一次数据返回的时间很长,说是数据返回不如说是服务器端因为超时断开了连接。经过查阅手册会发现,关于fgets的返回的条件为:碰到换行符(包括在返回值中)、EOF 或者已经读取了 length - 1 字节后停止(看先碰到那一种情况)。
问题就出在服务器端缓冲会话的时候是不会返回结束标志,也不返回换行符的情况。那么我们可以通过以下方法来解决这个问题。
设置一个返回长度$length = 1024。第一次时使用这个长度,当有数据返回时,取出数据的长度$len,然后根据返回的数据来计算还有多少剩余的数据,这样就可以根据$length与(剩余的长度+1)找出最小值$min。下次fgets时的返回长度修正为$min。这样就可以正常的判断返回数据的大小。部分代码如下:
1 <?php 2 function send($data /* String */) { 3 $result = ''; 4 5 $fp = fsockopen($this->url, $this->port, $errno, $errstr, 10); 6 7 if (!$fp) { 8 return null; 9 } else { 10 fputs($fp, $this->method." ".$this->uri." HTTP/1.1\r\n"); 11 fputs($fp, "Host: ".$this->url.":".$this->port."\r\n"); 12 fputs($fp, "Content-type: text/html;charset=".$this->charset."\r\n"); 13 fputs($fp, "Accept-Language: zh-cn\r\n"); 14 fputs($fp, "User-Agent: Mozilla/4.0(Compatible win32; MSIE)\r\n"); 15 fputs($fp, "Content-Length: ".strlen($data)."\r\n"); 16 fputs($fp, "Connection: close\r\n\r\n"); 17 fputs($fp, $data); 18 19 $len = -1; 20 $length = 1024; 21 while(!feof($fp)) { 22 $result .= fgets($fp, $length); 23 24 if (stripos($result, "\r\n\r\n") !== false) { 25 $start = stripos($result, "Content-Length:") + 15; 26 27 if ($start !== false && $len < 0) { 28 $end = stripos($result, "\r\n", $start); 29 $len = trim(substr($result, $start, stripos($result, "\r\n", $start) - $start)); 30 } 31 32 if ($len > 0) { 33 $str = substr($result, strpos($result, "\r\n\r\n") + 4); 34 $length = min($length, $len - strlen($str) + 1); 35 } 36 37 if ($length < 2) { 38 fclose($fp); 39 return $str; 40 } 41 } 42 } 43 } 44 }