之前,我们使用composer来安装workerman。接下来,我们开始使用一个简单的demo来初步了解它的流程。简单演示//http.phprequire__DIR__。'/vendor/autoload.php';useWorkerman\Worker;//创建一个Worker监听2345端口,使用http协议进行通信$http_worker=newWorker("http://0.0.0.0:2345");//启动4个进程对外提供服务$http_worker->count=4;//当收到浏览器发送的数据时,向浏览器回复helloworld$http_worker->onMessage=function($connection,$data){//向浏览器发送helloworld$connection->send('helloworld');};//运行workerWorker::runAll();复制自官网。首先直接使用它。来源。可以使用以下命令运行phphttp.phpstart//或winphphttp.phpconstructor在上面的示例代码中,创建了一个worker类并设置它监听2345端口,然后设置回调信息。然后它跑了。如果没有导入,一切都从新开始。让我们来看看新的时候做了什么。先贴出源码,一步步分析。publicfunction__construct($socket_name='',$context_option=array()){//保存所有worker实例。$this->workerId=\spl_object_hash($this);静态::$_workers[$this->workerId]=$this;static::$_pidMap[$this->workerId]=array();//获取自动加载根路径。$回溯=\debug_backtrace();$this->_autoloadRootPath=\dirname($backtrace[0]['file']);if(static::$_OS===OS_TYPE_LINUX&&version_compare(PHP_VERSION,'7.0.0','ge')){$php_uname=strtolower(php_uname('s'));//如果不是MacOS,则打开reusePort。如果($php_uname!=='darwin'){$this->reusePort=true;}}//套接字的上下文。如果($socket_name){$this->_socketName=$socket_name;$this->parseSocketAddress();如果(!isset($context_option['socket']['backlog'])){$context_option['socket']['backlog']=static::DEFAULT_BACKLOG;}$this->_context=\stream_context_create($context_option);}}首先,进入构造函数的第一步是为自己声明ID,通过对象的ID。spl_object_hash可以直接为对象生成一个唯一的ID。你可以理解为uuid的概念。那么下一步,准备开始迷茫了。static::$_workers[$this->workerId]=$this;static::$_pidMap[$this->workerId]=array();把自己放到Worker::$_workers这个静态变量中,然后初始化自己的pidMap。从表面上看,然后调用debug_backtrace获取命令的根目录,然后判断你是不是linux开启端口多路复用。if(static::$_OS===OS_TYPE_LINUX&&version_compare(PHP_VERSION,'7.0.0','ge')){$php_uname=strtolower(php_uname('s'));如果($php_uname!=='darwin'){$this->reusePort=true;//开始端口复用}}这个端口复用在linux和windows之间有局部的区别。第一关。然后我们开始解析我们的协议。解析协议后,设置stream_context_create的context对象。至此,初始化完成。我们来看协议解析protocolParse//parseSocketAddressprotectedfunctionparseSocketAddress(){if(!$this->_socketName){return;}//获取应用层通信协议和监听地址。列表($scheme,$address)=\explode(':',$this->_socketName,2);//检查应用层协议类。如果(!isset(static::$_builtinTransports[$scheme])){$scheme=\ucfirst($scheme);$this->protocol=\substr($scheme,0,1)==='\\'?$方案:'\\协议\\'。$计划;如果(!\class_exists($this->protocol)){$this->protocol="\\Workerman\\Protocols\\$scheme";如果(!\class_exists($this->protocol)){thrownewException("class\\Protocols\\$schemenotexist");}}if(!isset(static::$_builtinTransports[$this->transport])){thrownew\Exception('Badworker->transport'.\var_export($this->transport,true));}}else{$this->transport=$scheme;$local_socket=static::$_builtinTransports[$this->transport]。“:”。$地址;return$local_socket;}在此之前,我们需要先了解一下我们的协议。这里打开的话,还得另开一篇文章。所以我们只需要了解格式即可。一个套接字由三部分组成。首先是协议类型,http,tcp...等等。第二个是监听地址。0.0.0.0是监听本地地址。第三个是我们的港口。这里我们的端口是2345。//http协议//0.0.0.0监听地址//2345监听端口。http://0.0.0.0:2345这里监听本地2345端口做一个http协议服务器。接下来我们看一下解析协议的函数。第一步是根据我们提供的socketName获取对应的协议类型(http)和地址.list($scheme,$address)=\explode(':',$this->_socketName,2);然后去Worker::$_builtinTransports找到协议类型。这里包含了我们最基本的protocol.tcp,udp、unix和ssl。如果是最基本的,直接保存在$this->transport中。如果没有,那就有点麻烦了。$scheme=\ucfirst($scheme);//将http转换为Http$this->protocol=\substr($scheme,0,1)==='\\'?$方案:'\\协议\\'。$计划;//如果第一个是\,则直接保存到协议中。如果No,就是\Protocols\$scheme,显然我们是Protocols\Http.if(!\class_exists($this->protocol)){//如果类不存在,检查Workerman自己定义的协议。$this->protocol="\\Workerman\\Protocols\\$scheme";if(!\class_exists($this->protocol)){//如果没有找到,会报错。thrownewException("class\\Protocols\\$schemenotexist");}}//如果不存在,则报错。$this->transport默认为tcpif(!isset(static::$_builtinTransports[$this->transport])){thrownew\Exception('Badworker->transport'.\var_export($this->transport,true)));}从上面的代码可以看出,首先搜索php本身支持的协议或者自己写的协议,没有的话再找workerman本身的协议。如果是自己定义的协议,则基于tcp协议创建自己的协议。这里有几点,首先。协议的命名空间是什么?这是php自己定义的协议,包括以下文件://—访问本地文件系统http://—访问HTTP(s)URLsftp://—访问FTP(s)URLsphp://—访问单独的输入/输出流(I/Ostreams)zlib://—压缩流data://—数据(RFC2397)glob://—查找匹配的文件路径模式phar://—PHP存档ssh2://—SecureShell2rar://—RARogg://—音频流expect://—处理交互流当然上面的协议php都没有实现对应的Protocols。所以他们会去寻找WorkermanProtocols下的分析。至此,初始化完全完成。以上未处理的点,关于初始化的问题。在后续的过程中慢慢了解。$this->reusePort=true;//端口复用,只要系统不是mac和windows即可。这个值是真的。Worker::$_workers//这里保存所有的workerWorker::$_pidMap[$this->workerId]//从名字看就是存储的进程号。我稍后会处理它。
