我在测试workerman时下了如下的简单测试代码:
public function workerOnMessage($connection, $data)
{
$ip = $connection->getRemoteIp();
if ($ip == '127.0.0.1') {
$data = str_replace('\\"', '"', str_replace('\r\n', '', $data));
$data = ltrim($data, '"');
$data = rtrim($data, '"');
}
if ($data == '@') { //判断数据是不是@,作为心跳包
$connection->send('@');
}
if($data == '1'){
$str1 = "1111111111111111111111111111111111111111111111111111111111111111111";
for($i = 0; $i < 10000000; $i++){
$str1 .= '*';
}
$str2 = "2222222222";
$str3 = "3";
$connection->send($str2);
$connection->send($str1);
$connection->send($str3);
}
}
发现在客户端的情况如下:
$str2接收到,$str1接收到,但是$str3没接收到,这个是个什么问题?
workerman有内存保护机制,例如向客户端发送(尤其是广播)大数据时,由于客户端接收速度或者带宽问题,客户端不会立刻接收到所有数据。那么这些未发送完的数据就要缓冲在服务器内存里。例如向1000个客户端瞬间广播10M的数据,那么最坏的情况在内存瞬间可能要缓冲10G的数据,服务器内存就爆掉了。所以workerman有一个发送缓冲区的限制,默认是每个客户端1M的缓冲区,可以通过http://doc.workerman.net/315342 更改。如果超过这个限制,会触发http://doc.workerman.net/315150回调,在这个回调里开发者可以做一些处理比如停止后续发送等。如果onBufferFull回调触发后,服务端仍然发送数据并且缓冲区仍然是满的,会触发onError回调,并丢弃数据。
通过你的代码看到是服务端瞬间发送约10M的数据,对应客户端发送缓冲区会被填满,导致后面的数据被丢弃,所以后面的数据可能收不到。
解决办法
1、不要发送这么大的数据。
2、监听onBufferFull事件,对方缓冲区满了就不要发了
感谢回复,明白了。