请问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客户端画面
B客户端
每个连接进来都要简历一个新的线程,子线程和用户沟通,主线程负责接收连接
用libeven吧
看了一下代码是单进程、非阻塞、select模型实现的io复用。不过设置非阻塞的一行应该放错地方了,较好的实现io复用,是使用php的event扩展。swoole/workman 简单容易,何必费劲原生撸?