请问socket如何非阻塞?

我现在的项目需求是,需要给多个用户(浏览器客户端)推送 物体的轨迹,即每隔几秒推一次坐标 那么地图上的物体移动一次,但是有个问题就是当我在给一个客户端A推送的时,同时在新打开一个客户端 B那么就会无法连接 直到 A推送完,请问这个问题怎么解决啊?

推送代码(这个文件是由一个守护进程执行的,)

//类文件其它部分就不贴出来了
$server = new Locus_push();
$server->run();

public function run()
    {
        while (true) {
            if (!self::$redis) {
                self::$redis = new redis();
                self::$redis->connect('127.0.0.1');
            }
            $changes = $this->_sockets;
            $write  = NULL;
            $except = NULL;
            socket_select($changes, $write, $except, NULL);
            foreach ($changes as $key => $_sock) {
                socket_set_nonblock($_sock);
                if ($this->_socket == $_sock) {
                    //判断是不是新接入的socket

                    $this->e("--------------new---socket------------");
                    $this->e($_sock);
                    $this->e("--------------new---socket------------");


                    $newClient = socket_accept($_sock);
                    $line      = trim(socket_read($newClient, 1024));
                    $this->handshaking($newClient, $line);
                    $key                 = uniqid();
                    $this->_sockets[]    = $newClient;
                    $this->clients[$key] = [
                        'socket' => $newClient,
                        'hand'   => true
                    ];


                    $queue_key = "car_1_locus_queue";
                    while ($item = self::$redis->rPop($queue_key)) {
                        //根据每段坐标行驶时间 休息对应的秒数
                        $item_arr = json_decode($item, true);
                        sleep(ceil($item_arr['dur'] / 1000));
                        $this->send($newClient, $item);

                    }

                    echo "--------------new--socket--user---------\n";
                    var_dump($this->clients);
                    echo "--------------new--socket--user---------\n";
                } else {
                    $len    = 0;
                    $buffer = '';
                    //读取该socket的信息,注意:第二个参数是引用传参即接收数据,第三个参数是接收数据的长度
                    do {
                        $l      = socket_recv($_sock, $buf, 1000, 0);
                        $len    += $l;
                        $buffer .= $buf;
                    } while ($l == 1000);
                    $k = $this->getClient($_sock);
                    //如果接收的信息长度小于7,则该client的socket为断开连接
                    if ($len < 7) {
                        //给该client的socket进行断开操作,并在$this->sockets和$this->users里面进行删除
                        $this->close($k);
                        continue;
                    }
                    if (!$this->clients[$k]['hand']) {
                        $this->handshaking($_sock, $buffer);
                    } else {
                        //走到这里就是该client发送信息了,对接受到的信息进行处理
                        $client_msg = $this->message($buffer);
                        $client_msg_array = json_decode($client_msg, true);
                        if ($client_msg_array['type'] == 'get_car_locus') {
                            $queue_key = "car_1_locus_queue";
                           //这段就是行队列里面取数据,然后循环推送给用户
                           while ($item = self::$redis->rPop($queue_key)) {
                                //根据每段坐标行驶时间 休息对应的秒数
                                $item_arr = json_decode($item, true);
                                sleep(ceil($item_arr['dur'] / 1000));
                                foreach ($this->clients as $key => $client) {
                                    $this->send($client['socket'], $item);
                                }
                            }
                        } elseif ($client_msg_array['type'] == 'get_aircraft_locus') {}
                    }
                }
            }
        }
    }

A客户端画面

请问socket如何非阻塞?

B客户端

请问socket如何非阻塞?

UKNOW
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
《L05 电商实战》
从零开发一个电商项目,功能包括电商后台、商品 & SKU 管理、购物车、订单管理、支付宝支付、微信支付、订单退款流程、优惠券等
讨论数量: 3

每个连接进来都要简历一个新的线程,子线程和用户沟通,主线程负责接收连接

3年前 评论

看了一下代码是单进程、非阻塞、select模型实现的io复用。不过设置非阻塞的一行应该放错地方了,较好的实现io复用,是使用php的event扩展。swoole/workman 简单容易,何必费劲原生撸?

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!