workerman http分包
http协议是应用层协议,所以从socket的 读取缓冲池(readbuff) 读取 的都是 tcp协议 内包含的数据(应用层协议头+应用层数据)
那么就面临着这样一个问题,有可能一个tcp连接,快速的向服务端发送请求,那么此时readbuff里面就有可能有多个请求的数据,所以这次我们研究的就是workman的http分包
背景
因为workman可根据安装扩展来使用多种IO模型,select ,event等。此处我用event来讲解(epoll模型)
后面的代码都是简略代码,
workerman监听连接
work进程启动时,开启socket_accpet阻塞监听端口,等待客户端连接
Worker.php
//socket此处的socket参数和accept返回去的socket不是同一个
public function acceptConnection($socket){
$new_socket = stream_socket_accept($socket, 0, $remote_address);
$connection = new TcpConnection($new_socket, $remote_address);
}
TcpConnection.php
class TcpConnection
{
public _recvBuffer; //从readbuff内读取到的数据
public function __construct($socket, $remote_address = '')
{
//这里是event事件 注册了一个回调事件。如果_socketreadbuff内有数据,那么就会出$this->baseRead()
Worker::$globalEvent->add($this->_socket, EventInterface::EV_READ, array($this, 'baseRead'));
}
public function baseRead()
{
//ssl,之后在解读里面的代码
//读取readbuff的数据,此时有可能有多个请求数据包
$buffer = fread($socket, self::READ_BUFFER_SIZE);
//获取当前数据包的长度, !!!!!!!!!!!!读取这一行直接去看下一个代码块!!!!!!
$this->_currentPackageLength = $parser::input($this->_recvBuffer, $this);
}
}
Http.php
function input($recv_buffer, TcpConnection $connection)
{
//如果没有读到 http请求头的结束符(\r\n\r\n),那么说明readbuff里面没有一个http完整请求,此时返回0
if (!strpos($recv_buffer, "\r\n\r\n")) {
return 0;
}
//获取头部信息
list($header,) = explode("\r\n\r\n", $recv_buffer, 2);
$method = substr($header, 0, strpos($header, ' '));
//根据method方法(POST GET)来获取请求的大小
return static::getRequestSize($header, $method);
}
static function getRequestSize()
{
//正则出 content-Length后面的值,这个值代表了请求数据。请求数据+请求头就是完整的请求大小。为什么+4,4就是\r\n\r\n
if (preg_match("/\r\nContent-Length: ?(\d+)/i", $header, $match)) {
$content_length = isset($match[1]) ? $match[1] : 0;
return $content_length + strlen($header) + 4;
}
}