Swoole的Server端常用方法和属性


/**
 * Reactor是master中的独立的几个线程, 在该线程中的每一个子线程中都运行着epoll函数的实例.
 * Swoole所有对于事件的监听, 都会在这些线程中实现.比如,来自客户端的连接, 本地通信的管道.以及,异步操作的文件.文件描述符.都会注册在这些epoll中
 *
 * timer基于Reactor线程中的epoll实例的timeout机制,实现的.
 * timer进程是基于,epoll实例的Reactor线程来运行的
 * 在taskWorker中是没有Reactor线程的, 所以不能调用swoole的异步IO的这些函数.
 * 因此taskWorker 中的定时器,是使用的系统的定时器. 依照个人经验,建议不要在task中搞定时器.
 * Swoole是使用堆存放timer,提高检索效果.
 * tick是支持第三个参数的, 用户的自定义数据.同时ticker的运行和返回值, 是在同一个worker进程中的.
 * tick会返回一个指定的timer_id,如果需要,可以使用swoole_timer_clear清除指定的定时器.
 */
 
 /**
 *task 传递数据的大小, 当数据小于8K, 会用管道进行传递.
 *  当大于8K 的时候, 会先行,写入一个临时文件当中\tmp
 *  当接到的实际的任务之后, 会去读取这个文件将, 将数据读取出来.
 *task传递对象, 可以通过对象序列化, 来传递一个对象的拷贝. 并非一个对象的引用.比如说,传一个对象,可以修改对象的数据,但是并不会反应到传送前的worker进程当中.
 *  因为task进程和worker进程,是连个不同的进程, 不在同一个内存空间.task中对对象的操作, 并不会反应到worker当中
 *  数据库连接, 网络连接对象不可传递.
 *task的onfinish回调会发回调用task方法的worker进程
 */
 
 /**
 * timer基于epoll的timeout机制,实现的.
 * timer进程是基于,epoll实例的Reactor线程来运行的
 * 在taskWorker中是没有Reactor线程的, 所以不能调用swoole的异步IO的这些函数.
 * 因此taskWorker 中的定时器,是使用的系统的定时器.
 * Swoole是使用堆存放timer,提高检索效果.
 * tick是支持第三个参数的, 用户的自定义数据.同时ticker的运行和返回值, 是在同一个worker进程中的.
 * tick会返回一个指定的timer_id,如果需要,可以使用swoole_timer_clear清除指定的定时器.
 */
 
注解:
    Swoole的很多方法, 不仅是一个方法, 同时也是支持回调的用法的.
    进直接调用该方法,则使用该方法的特性进行操作如$serv->close($fd)关闭了该连接.
    
    也可以在构造函数中绑定一个回调$this->serv->on('Close', [$this, 'onClose']);
    这种用法,像极了call_user_func_arr();
    以前KR那边的的Swoole是直接写在一个方法中的所以CLOSE直接这么干:
    		$serv->on('Close', function($server, $fd) {
    		    #逻辑代码
            }
    现在的话,我是直接在一个类中单独绑定所有的需要事件,声明好所有的回调.
    如下:
		# 激活redis
		$this->Redis();

		# bind Callback
		$this->serv->on('WorkerStart', [$this, 'onWorkerStart']);
		$this->serv->on('Connect', [$this, 'onConnect']);
		$this->serv->on('Receive', [$this, 'onReceive']);
		$this->serv->on('Close', [$this, 'onClose']);

		$this->serv->on('Task', [$this, 'onTask']);
		$this->serv->on('Finish', [$this, 'onFinish']);
		$this->serv->start();
    代码的话,具体可以参考.socket章节下的Swoole测试代码


    
    以下方法 [有无回调] 代表该方法是否支持事件回调函数的用法.
    
    所谓回调用法如close最具有代表性:
        # 关闭操作
        bool swoole_server->close(int $fd, bool $reset = false);        
        为关闭某个$fd的连接,返回bool值.
        # 回调操作
        TCP客户端连接关闭后,在worker进程中回调此函数。函数原型:        	
        # 在构造函数中绑定该方法
        $this->serv->on('Close', [$this, 'onClose']);
        # 有客户端关闭的时候,会触发该方法
        function onClose(swoole_server $server, int $fd, int $reactorId);
        	# 连接关闭回调
        	public function onClose($serv, $fd, $from_id)
        	{
        		echo "Client {$fd} close connect\n";
        	}
        	此时作为连接关闭会的事件触发方法.
        	
        
  • 日志
各种方法,暂未标注,是否支持事件回调用法.
以及,常规使用和回调函数的用法.
日后再补吧.可以参考手册以及我的测试代码

  • 开头
# 激活Swoole, 侦听指定IP和端口
$swSwoole = new Swoole\Websocket\Server('IP','PORT')

官方案例:
    创建一个异步Server对象。 
$serv = new swoole_server(string $host, int $port = 0, int $mode = SWOOLE_PROCESS,int $sock_type = SWOOLE_SOCK_TCP);
    $host参数用来指定监听的ip地址,如127.0.0.1,或者外网地址,或者0.0.0.0监听全部地址
        IPv4使用 127.0.0.1表示监听本机,0.0.0.0表示监听所有地址
        IPv6使用::1表示监听本机,:: (相当于0:0:0:0:0:0:0:0) 表示监听所有地址
    $port监听的端口,如9501
        如果$sock_type为UnixSocket Stream/Dgram,此参数将被忽略
        监听小于1024端口需要root权限
        如果此端口被占用server->start时会失败
    $mode运行的模式,swoole提供了3种运行模式,默认为SWOOLE_PROCESS多进程模式
    $sock_type指定Socket的类型,支持TCP、UDP、TCP6、UDP6、UnixSocket Stream/Dgram 6种
    使用$sock_type | SWOOLE_SSL可以启用SSL隧道加密。启用SSL后必须配置ssl_key_file和ssl_cert_file
    1.7.11版本增加了对Unix Socket的支持,详细请参见 /wiki/page/16.html
    构造函数中的参数与swoole_server::addlistener中是完全相同的
    监听端口失败,在1.9.16以上版本会抛出异常,可以使用try/catch捕获异常,在1.9.16以下版本抛出致命错误
    高负载的服务器,请务必调整Linux内核参数
    3种Server运行模式介绍


  • 关于ON注册Server的事件回调函数。
注册Server的事件回调函数。
bool swoole_server->on(string $event, mixed $callback);
    第1个参数是回调的名称, 大小写不敏感,具体内容参考回调函数列表,事件名称字符串不要加on
    第2个函数是回调的PHP函数,可以是函数名的字符串,类静态方法,对象方法数组,匿名函数。
重复调用on方法时会覆盖上一次的设定


如例:
    $serv = new swoole_server("127.0.0.1", 9501);
    $serv->on('connect', function ($serv, $fd){
        echo "Client:Connect.\n";
    });
    $serv->on('receive', function ($serv, $fd, $from_id, $data) {
        $serv->send($fd, 'Swoole: '.$data);
        $serv->close($fd);
    });
    $serv->on('close', function ($serv, $fd) {
        echo "Client: Close.\n";
    });
    $serv->start();


我的例子:
    	/**
	 * socket constructor.
	 * @author  liuhao <lh@btctrade.com>
	 * 在构造函数中声明所有需要使用的回调函数
	 * 同时也要给这些回调函数准备一些函数
	 */
	public function __construct()
	{
		$this->serv = new swoole_server("127.0.0.1", 9999);
		$this->serv->set([
			'worker_num'      => 2,
			'daemonize'       => false,
			'max_request'     => 100000,
			'dispath_mode'    => 2,
			'debug_mode'      => 1,
			'task_worker_num' => 2,
		]);

		# bind Callback
		$this->serv->on('WorkerStart', [$this, 'onWorkerStart']);
		$this->serv->on('Connect', [$this, 'onConnect']);
		$this->serv->on('Receive', [$this, 'onReceive']);
		$this->serv->on('Close', [$this, 'onClose']);

		$this->serv->on('Task', [$this, 'onTask']);
		$this->serv->on('Finish', [$this, 'onFinish']);
		$this->serv->start();
	}



  • 关于OPEN和Connect [有回调]
$swSwoole->On('open', function($server, $req){
    
});
OPEN为, 前端连接swoole成功后的触发的回调.
该连接,表示已握手成功后连接畅通触发.

  • 关于CLOSE [有回调]
$swSwoole->On('close', function($server,$req){
    
});

CLOSE表示连接断开后触发的操作,
该操作属于被动操作, 即:不是用来关闭连接用的.
一般我用来做: 连接断开, 从数据库中删除该用户的连接ID(Swoole连接时分配的, 我将它存在了redis,便于后续的群发推送)
可以直接操作CLOSE来关闭某个连接

swoole_server->close(int $fd, bool $reset = false);
    操作成功返回true,失败返回false.
    Server主动close连接,也一样会触发onClose事件。
    不要在close之后写清理逻辑。应当放置到onClose回调中处理
    $reset设置为true会强制关闭连接,丢弃发送队列中的数据


  • 关于WorkerStart
/**
 * worker 进程开始时的回调,
 * 该回调, 会在task和worker创建之初,进行创建.
 * 所以他分不清,task和worker, 也可以理解为, worker和task同时都走这里
 * $serv->taskworker 可以用来判断他是数据worker 还是task
 * 通过var_dump($worker_id)也可以得知;
 */
$swServer->On('WorkerStart', function ($server, $workerId) use($redis){
}
今天在使用该方法进行,
多进程处理时,遇到了一个问题: 
    在On WorkerStart 下直接使用$redis->sMembers()获取无序集合内的所有信息时
    ,发生错误但是能用, 提示:
    ERROR	zm_deactivate_swoole (ERROR 503): Fatal error: Uncaught RedisException: read error on connection
    
    如果在WorkerStart 的中使用原生的PHP链接redis方式, 是没有问题的. 但是使用封装好的redis单例类, 则报错....
    
    要命的时, 我原来以为,redis未使用pconnect连接的原因,事实证明不是这个原因.
    随后我将$redis->sMembers();放在多进程判断if(进程=XX)里面的定时器中, 
    该问题,解决, 郁闷.
    具体是为什么? 我不太清楚, 查了下手册, 然而手册并不完善. 
    我认为是:
        On worker方法, 是worker进程开始后的回调.
        而worker进程开始是多个的.
    
    
遇到一个逻辑问题, 是虽然使用原生的PHP链接redis, 解决的在ON WorkerStart中封装的redis类报错问题. 但是, 由于该回调是, Swoole进程开始运行时的回调. 
在这里获取到的用户链接Swoole的socket继承ID是不准确的, 进程开始时获取的时进程还未运行时的数据, 
所以, 后来我又将redis->sMembers();放在了定时器中.不间断获取.
以及在,ON open,及用户成功连接时,即刻推送一次.
    
  • 关于connection_info
swoole_server->connection_info函数用来获取连接的信息,别名是swoole_server->getClientInfo

function swoole_server->connection_info(int $fd, int $extraData, bool $ignoreError = false)
    如果传入的fd存在,将会返回一个数组
    连接不存在或已关闭,返回false
    第3个参数表示是否忽略错误,如果设置为true,即使连接关闭也会返回连接的信息

实例:
    $serv->connection_info($fd);
    $fdinfo = $serv->connection_info($fd);
        var_dump($fdinfo);
        array(5) {
          ["reactor_id"]=>
          int(3)
          ["server_fd"]=>
          int(14)
          ["server_port"]=>
          int(9501)
          ["remote_port"]=>
          int(19889)
          ["remote_ip"]=>
          string(9) "127.0.0.1"
          ["connect_time"]=>
          int(1390212495)
          ["last_time"]=>
          int(1390212760)
        }

$udp_client = $serv->connection_info($fd, $from_id);
var_dump($udp_client);

    reactor_id 来自哪个reactor线程
    server_fd 来自哪个server socket 这里不是客户端连接的fd
    server_port 来自哪个Server端口
    remote_port 客户端连接的端口
    remote_ip 客户端连接的ip
    connect_time 连接到Server的时间,单位秒
    last_time 最后一次发送数据的时间,单位秒
    close_errno 连接关闭的错误码,如果连接异常关闭,close_errno的值是非零,可以参考Linux错误信息列表
    websocket_status [可选项] WebSocket连接状态,当服务器是Swoole\WebSocket\Server时会额外增加此项信息
    uid [可选项] 使用bind绑定了用户ID时会额外增加此项信息
    ssl_client_cert [可选项] 使用SSL隧道加密,并且客户端设置了证书时会额外添加此项信息


一般我的使用方式是, 在连接的时候即onConnect()中使用该函数,获取客户端信息,存储起来.用作统计.

  • 关于stats
得到当前Server的活动TCP连接数,启动时间,accpet/close的总次数等信息。
array swoole_server->stats();

返回的结果数组示例:
    array (
        'start_time' => 1409831644,
        'connection_num' => 1,
        'accept_count' => 1,
        'close_count' => 0,
        'task_queue_num' => 10,
        'task_queue_bytes' => 65536,
    );
    start_time 服务器启动的时间
    connection_num 当前连接的数量
    accept_count 接受了多少个连接
    close_count 关闭的连接数量
    tasking_num 当前正在排队的任务数
    task_queue_num 消息队列中的Task数量
    task_queue_bytes 消息队列的内存占用字节数


一般我的用法是在连接时,$serv->stats()使用该函数,判断一下服务器状态,是否允许连接.

  • 关于connection_list
用来遍历当前Server所有的客户端连接,connection_list方法是基于共享内存的,不存在IOWait,遍历的速度很快。另外connection_list会返回所有TCP连接,而不仅仅是当前worker进程的TCP连接。

我认为需要切记的是: 
    该函数, 会返回所有的TCP连接,而不仅仅是当前worker进程的TCP连接.
    
实例:
    # 分批次发送, 官方实例
    $start_fd = 0;
    while(true)
    {
        # connection_list函数获取现在连接中的fd
        $conn_list = $ws->connection_list($start_fd, 100);   # 获取从fd之后一百个进行发送
        var_dump($conn_list);
        echo count($conn_list);

        if($conn_list === false || count($conn_list) === 0)
        {
            echo "finish\n";
            return;
        }

        $start_fd = end($conn_list);
        
        foreach($conn_list as $fd)
        {
            $ws->push($fd, $msg);
        }
    }
    
    # 我的实例
			# 推送所有在线的客户端
			$start_fd = 0;
			while (true) {
				# 获取所有在线的客户端连接
				$conn_list = $serv->connection_list($start_fd, 100);
				if (isset($conn_list) && !empty($conn_list)) {
					foreach ($conn_list as $v1) {
						# 不向自身, 返回消息
						if ($v1 == $data['fd']) continue;
						# 该连接处于有效状态
						if ($serv->exist($v1)) {
							# 发送消息
							$serv->send($v1, '这里是全局推送信息,你是第: ' . $v1 . '连接的客户端' . '处理你的task为:' . $task_id);
						}
					}
				} else {
					break;
				}
			}
    
  • 关于task异步 [有回调]

/**
 *task 传递数据的大小, 当数据小于8K, 会用管道进行传递.
 *  当大于8K 的时候, 会先行,写入一个临时文件当中\tmp
 *  当接到的实际的任务之后, 会去读取这个文件将, 将数据读取出来.
 *task传递对象, 可以通过对象序列化, 来传递一个对象的拷贝. 并非一个对象的引用.比如说,传一个对象,可以修改对象传过来的数据在本进程中使用,但是并不会反应到传送前的worker进程当中.
 *  因为task进程和worker进程,是连个不同的进程, 不在同一个内存空间.task中对对象的操作, 并不会反应到worker当中
 *  数据库连接, 网络连接对象不可传递.
 *task的onfinish回调会发回调用task方法的worker进程
 */
 
 
使用Task功能,必须先设置 task_worker_num,并且必须设置Server的onTask和onFinish事件回调函数。
int swoole_server::task(mixed $data, int $dst_worker_id = -1) 

    $data要投递的任务数据,可以为除资源类型之外的任意PHP变量
    $dst_worker_id可以制定要给投递给哪个task进程,传入ID即可,范围是0 - (serv->task_worker_num -1)
    调用成功,返回值为整数$task_id,表示此任务的ID。如果有finish回应,onFinish回调中会携带$task_id参数
    调用失败,返回值为false
    未指定目标Task进程,调用task方法会判断Task进程的忙闲状态,底层只会向处于空闲状态的Task进程投递任务。如果所有Task进程均处于忙的状态,底层会轮询投递任务到各个进程。可以使用 server->stats 方法获取当前正在排队的任务数量。
    1.8.6版本增加了第三个参数,可以直接设置onFinish函数,如果任务设置了回调函数,Task返回结果时会直接执行指定的回调函数,不再执行Server的onFinish回调


需要注意的是:
    swoole_server->task/taskwait/finish 3个方法当传入的$data数据超过8K时会启用临时文件来保存。当临时文件内容超过 server->package_max_length 时底层会抛出一个警告。此警告不影响数据的投递,过大的Task可能会存在性能问题。
    
task底层使用Unix Socket管道通信,是全内存的,没有IO消耗。单进程读写性能可达100万/s,不同的进程使用不同的管道通信,可以最大化利用多核。

该方法是异步回调的.
一般我的用法是, 在swoole_server中的onReceive或者swoole_websocket_server中的onMessage.
中即,接受到用户的请求后调用task进程进行异步处理.$serv->task($data);
然后在ontask进程中进行数据库操作或者,广播消息.

如例:


	# 接收数据回调
	public function onReceive(swoole_server $serv, $fd, $from_id, $data)
	{
		echo "Get Message From Client {$fd}: {$data}\n";

		# 组建需要异步的数据
		$data = [
			'task'   => 'task_1',   # 该任务命名为task_1,方便后边测试
			'params' => $data,      # 传递的参数
			'fd'     => $fd         # 客户端的描述符
		];
		$serv->task(json_encode($data));
	}

	# 异步回调
	public function onTask($serv, $task_id, $from_id, $data)
	{
		echo "This task {$task_id} from Worker {$from_id}\n";
		echo "Data: {$data}\n";
		var_dump($data);
		# 转换接收到的JSON数据
		$data = json_decode($data, true);
		# 数据接收到的数据
		echo "Receive Task : {$data['task']}\n";
		# 返回用户数据
		$serv->send($data['fd'], $data['params']);

		return "Finished";
	}

	# 异步结束回调(swoole机制, task运行完毕,如果finish回调存在,则返回到onFinish中)
	public function onFinish($serv, $task_id, $data)
	{
		echo "Task {$task_id} finish\n";
		echo "Result: {$data}\n";
	}

  • 关于finish [有回调]
Tash的onfinish方法回调会调用task方法的worker进程,而不是其他worker进程(worker是有多个的).
此函数用于在task进程中通知worker进程,投递的任务已完成。此函数可以传递结果数据给worker进程。
$serv->finish("response");
使用swoole_server::finish函数必须为Server设置onFinish回调函数。此函数只可用于task进程的onTask回调中

    finish方法可以连续多次调用,Worker进程会多次触发onFinish事件
    在onTask回调函数中调用过finish方法后,return数据依然会触发onFinish事件


swoole_server::finish是可选的。如果worker进程不关心任务执行的结果,不需要调用此函数
在onTask回调函数中return字符串,等同于调用finish


如例子:
	# 异步回调
	public function onTask($serv, $task_id, $from_id, $data)
	{
		echo "This task {$task_id} from Worker {$from_id}\n";
		echo "Data: {$data}\n";
		var_dump($data);
		# 转换接收到的JSON数据
		$data = json_decode($data, true);
		# 数据接收到的数据
		echo "Receive Task : {$data['task']}\n";
		# 返回用户数据
		$serv->send($data['fd'], $data['params']);
        # 直接返回这个, 也可调用onFinish方法
		return "Finished";
	}

	# 异步结束回调(swoole机制, task运行完毕,如果finish回调存在,则返回到onFinish中)
	public function onFinish($serv, $task_id, $data)
	{
		echo "Task {$task_id} finish\n";
		echo "Result: {$data}\n";
	}


  • 关于Receive和message [有回调]
两者在用的时候,单纯从用的角度来讲,性质是一样的.
不同的是message是websocket的方法
function onReceive(swoole_server $server, int $fd, int $reactor_id, string $data);

    $server,swoole_server对象
    $fd,TCP客户端连接的唯一标识符
    $reactor_id,TCP连接所在的Reactor线程ID
    $data,收到的数据内容,可能是文本或者二进制内容

    关于$fd和$reactor_id 详细的解释
    未开启swoole的自动协议选项,onReceive回调函数单次收到的数据最大为64K
    Swoole支持二进制格式,$data可能是二进制数据

  • 关于send向客户端发送数据
bool swoole_server->send(int $fd, string $data, int $extraData = 0);
    $data,发送的数据,TCP协议最大不得超过2M,可修改 buffer_output_size 改变允许发送的最大包长度
    UDP协议不得超过65507,UDP包头占8字节, IP包头占20字节,65535-28 = 65507
    UDP服务器使用$fd保存客户端IP,$extraData保存server_fd和port
    发送成功会返回true
    发送失败会返回false,调用$server->getLastError()方法可以得到失败的错误码
    
    
如例子:
    	# 异步回调
	public function onTask($serv, $task_id, $from_id, $data)
	{
		echo "This task {$task_id} from Worker {$from_id}\n";
		echo "Data: {$data}\n";
		$data = json_decode($data, true);
		# 向该客户端发送数据
		$serv->send($data['fd'], '定时器10秒后发送的测试消息' . time());

		return 'Finished';
	}

  • 关于timer定时器的ticker和after [有回调]
int swoole_timer_tick(int $ms, callable $callback, mixed $user_param);
    tick定时器,可以自定义回调函数
    worker进程结束运行后,所有定时器都会自动销毁
    tick/after定时器不能在swoole_server->start之前使用
    
    用法案例:
        # 在workerStart中,直接用,以及单独声明一个回调.
        # 同时worker中激活了一个test对象, 而后在ticker的回调中调用得到.
        # 说明两者的变量时可以通用的, 在同一作用域.
	/**
	 * worker 进程开始时的回调,
	 * 该回调, 会在task和worker创建之初,进行创建.
	 * 所以他分不清,task和worker, 也可以理解为, worker和task同时都走这里
	 * $serv->taskworker 可以用来判断他是数据worker 还是task
	 * 通过var_dump($worker_id)也可以得知;
	 */
	public function onWorkerStart($serv, $worker_id)
	{
		echo "onWorkerStart: {$worker_id} \n";
		# 指定某一个worker才运行
		if ($worker_id == 1) {
			# 定时器,写法1
			/*	swoole_timer_tick(1000, function ($timer_id, $params) {
					echo "Timer Tick Params: {$params}\n" . time() . PHP_EOL;
				}, 'hello world');*/
			# 定时器,写法2,利用单独的回调,用于测试,ticker和worker的变量能否通用.
			$this->test = new Test();
			$this->test->index = 100;
			$serv->tick(1000, [$this, 'onTicker'], 'Hello Ticker');
		}

	}
	
	# ticker定时器的回调
	public function onTicker($timer_id, $params = '')
	{
		echo "This is Ticker Timer {$timer_id}\n";
		# 正常输入, 在OnworkerStart中赋值的对象
		var_dump($this->test->index);
	}
    
    # 官方案例
    
    在onReceive中使用
    function onReceive($server, $fd, $from_id, $data) {
        $server->tick(1000, function() use ($server, $fd) {
            $server->send($fd, "hello world");
        });
    }
    
    在onWorkerStart中使用, 而onWorkerStart启动的时候,
    是同时启动的worker和task所以此处需要特别处理.
    
    低于1.8.0版本task进程不能使用tick/after定时器,所以需要使用$serv->taskworker进行判断
    task进程可以使用addtimer间隔定时器
    function onWorkerStart(swoole_server $serv, $worker_id)
    {
        if (!$serv->taskworker) {
            $serv->tick(1000, function ($id) {
                var_dump($id);
            });
        }
        else
        {
            $serv->addtimer(1000);
        }
    }


swoole_server->after(int $after_time_ms, mixed $callback_function);
    swoole_server::after函数是一个一次性定时器,执行完成后就会销毁
    
    $after_time_ms 指定时间,单位为毫秒
    $callback_function 时间到期后所执行的函数,必须是可以调用的。callback函数不接受任何参数
    低于1.8.0版本task进程不支持after定时器,仅支持addtimer定时器

    $after_time_ms 最大不得超过 86400000
    此方法是swoole_timer_after函数的别名

用法和ticker相同,不在详细举例,只举一个简单的例子
	# 接收客户端数据的回调
	public function onReceive( $serv, $fd, $from_id, $data)
	{
		echo "Get Message From Client {$fd}: {$data}\n";

		# 由此处可知,该回调为worker的回调,并非taskworker
		if ($serv->taskworker) {
			echo 'This is TaskWorker' . PHP_EOL;
		} else {
			echo 'This is Worker' . PHP_EOL;
		}
		# 10秒钟后进行推送
		swoole_timer_after(10000, function () use ($serv, $fd) {
			$serv->task(json_encode(['fd' => $fd]));

		});

	}


  • 关于exists判断该描述符(fd)的客户端是否在线
bool function swoole_server->exist(int $fd)
检测fd对应的连接是否存在。
$fd对应的TCP连接存在返回true,不存在返回false
此接口是基于共享内存计算,没有任何IO操作
swoole_server->exist在1.7.18以上版本可用

案例:
    在全局广播中, 想所有在线客户端推送 时,判断该连接是否正常在线.
		# 推送所有在线的客户端
		$start_fd = 0;
		while (true) {
			# 获取所有在线的客户端连接
			$conn_list = $serv->connection_list($start_fd, 100);
			if (isset($conn_list) && !empty($conn_list)) {
				foreach ($conn_list as $v1) {
					# 不向自身, 返回消息
					if ($v1 == $data['fd']) continue;
					# 该连接处于有效状态
					if ($serv->exist($v1)) {
						# 发送消息
						$serv->send($v1, '这里是全局推送信息,你是第: ' . $v1 . '连接的客户端' . '处理你的task为:' . $task_id);
					}
				}
			} else {
				break;
			}
		}
		
  • 手动握手onHandShake
function onHandShake(swoole_http_request $request, swoole_http_response $response);

在WebSocket开发中, Swoole是进行自动握手的, 如果想要手动握手, 可以使使用这个. 

onHandShake事件回调是可选的
设置onHandShake回调函数后不会再触发onOpen事件,需要应用代码自行处理
onHandShake函数必须返回true表示握手成功,返回其他值表示握手失败
内置的握手协议为Sec-WebSocket-Version: 13,低版本浏览器需要自行实现握手

例如:
    $server->on('handshake', function (\swoole_http_request $request, \swoole_http_response $response) {}
    通过:
         $request->header;
         来获取请求头.
  
        $response->header($key, $val);
        来设置响应头.
        
    主体思想,即为, $request获取请求头, 得到key,处理后$response响应.
    具体操作可查看官方操作.


  • 关于setting属性
swoole_server::set()函数所设置的参数会保存到swoole_server::$setting属性上。在回调函数中可以访问运行参数的值。
    在swoole-1.6.11+可用

官方案例:
$serv = new swoole_server('127.0.0.1', 9501);
$serv->set(array('worker_num' => 4));

echo $serv->setting['worker_num'];

  • 关于worker_id属性
得到当前Worker进程的编号,包括Task进程。
int $server->worker_id;
这个属性与onWorkerStart时的$worker_id是相同的。

    Worker进程编号范围是[0, $serv->setting['worker_num'])
    task进程编号范围是[$serv->setting['worker_num'], $serv->setting['worker_num'] + $serv->setting['task_worker_num'])

    工作进程重启后worker_id的值是不变的


  • 关于 taskworker属性
布尔类型

    true表示当前的进程是Task工作进程
    false表示当前的进程是Worker进程

    此属性在swoole-1.7.15以上版本可用

  • 关于connections 属性

TCP连接迭代器,可以使用foreach遍历服务器当前所有的连接,此属性的功能与swoole_server->connnection_list是一致的,但是更加友好。遍历的元素为单个连接的fd。

注意$connections属性是一个迭代器对象,不是PHP数组,所以不能用var_dump或者数组下标来访问,只能通过foreach进行遍历操作。

foreach($server->connections as $fd)
{
    $server->send($fd, "hello");
}

echo "当前服务器共有 ".count($server->connections). " 个连接\n";

    此属性在1.7.16以上版本可用
    连接迭代器依赖pcre库(不是PHP的pcre扩展),未安装pcre库无法使用此功能
    所以一般我都用swoole_server->connections_list();

转载于:https://my.oschina.net/chinaliuhan/blog/3063754

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值