在PHP中作为客户端与服务器端使用socket进行通信时,一般我们使用fsockopen,但在使用这个函数进行通信时,有时候发现数据的反应时间特别长,更有甚者能达到1分钟。以下是代码片段:
1 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 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 }