关于TcpConnection的send函数

0
$len = @fwrite($this->_socket, $send_buffer);
// send successful.
if ($len === strlen($send_buffer)) {
return true;
}
// Send only part of the data.
if ($len > 0) {
$this->_sendBuffer = substr($send_buffer, $len);
} else {
// Connection closed?
if (!is_resource($this->_socket) || feof($this->_socket)) {
self::$statistics++;
if ($this->onError) {
try {
call_user_func($this->onError, $this, WORKERMAN_SEND_FAIL, 'client closed');
} catch (\Exception $e) {
Worker::log($e);
exit(250);
} catch (\Error $e) {
Worker::log($e);
exit(250);
}
}
$this->destroy();
return false;
}
$this->_sendBuffer = $send_buffer;
}
Worker::$globalEvent->add($this->_socket, EventInterface::EV_WRITE, array($this, 'baseWrite'));

这段代码中 当$len != strlen($send_buffer)的时候,为什么不继续 fwrite将剩余的数据发送出去,而要去监听
baseWrite函数, 在baseWrite里将剩余数据发送出去

已邀请:

walkor

赞同来自: sayliu 254135495 blogdaren zhuxiaoyu

$len != strlen($send_buffer) 说明缓冲区满了,暂时无法再次发送数据了。
再次调用fwrite很大的几率也是发送不了,所以要等待socket缓冲区的数据被对方接收socket缓冲区可写才能再次调用fwrite发送。


类似一个物流公司,有一个人(进程)负责发货(发送数据),这个人(进程)有很多仓库(链接)。一个仓库(链接)装满了(socket写缓冲区满),再往里放货物放不下了(fwrite返回0),所以要等待仓库的货物全部或者部分发出去(操作系统把socket缓冲区的数据发给对方),仓库有空地儿才能再次向里面放货物。但是这个人(进程)又不能在那里傻等(阻塞等待),万一货物永远都发不出去呢(进程永久阻塞等待)?岂不是不是很亏,这个时间这个人(进程)可以给其它仓库装货物呢(给其它链接发送数据)。所以这个人设置了一个机制(io复用机制,类似epoll),当货物发出仓库又有地方可以放新货物的时候通知他(socket可写事件),这个人继续向里面放货物(调用baseWrite)。这样这个人通过这种类似通知机制(epoll)大大提高了整个物流系统的吞吐量。

要回复问题请先登录注册