php80

Issue #66 resolved
ling created an issue

[root@6faaf20f5253 lumen-template]# php80 -v
PHP 8.0.3 (cli) (built: Mar 2 2021 16:37:06) ( NTS gcc x86_64 )
Copyright (c) The PHP Group
Zend Engine v4.0.3, Copyright (c) Zend Technologies
with Zend OPcache v8.0.3, Copyright (c), by Zend Technologies

[root@6faaf20f5253 lumen-template]# php80 --ri event

event

Event support => enabled
Sockets support => enabled
Debug support => disabled
Extra functionality support including HTTP, DNS, and RPC => enabled
OpenSSL support => enabled
Thread safety support => disabled
Extension version => 3.0.2r1
libevent2 headers version => 2.0.21-stable

[root@6faaf20f5253 swoole-test]# php80 epoll-server.php 5005
Segmentation fault

<?php
/**
 * Created by Ling.
 * Created on 2021/3/19 15:32
 * @email: L_ing1992@163.com
 */

set_time_limit(0);

if ($argc != 2) // 判断 指令 参数个数
{
    printf("usage: php epoll-server.php port\n");
    return -1;
}

$eventSupportedMethods = Event::getSupportedMethods();
if (!in_array('epoll', $eventSupportedMethods)) {
    die(' system not support epoll !!!');
}

$context = stream_context_create();
// 无法确下面设置是否生效 !
stream_context_set_option($context, 'socket', 'SO_REUSEADDR', true);
stream_context_set_option($context, 'socket', 'SO_KEEPALIVE', true);

//$flags 默认值为: STREAM_SERVER_BIND | STREAM_SERVER_LISTEN;
//$streamServerSocket = stream_socket_server('tcp://0.0.0.0:' . $argv[1], $errno, $errStr, context: $context);  // php 80
$streamServerSocket = stream_socket_server('tcp://0.0.0.0:' . $argv[1], $errno, $errStr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $context);

if ($streamServerSocket === false) {
    die('stream_socket_server() failed !!!');
}
stream_set_blocking($streamServerSocket, false);

$eventConfig = new EventConfig();
foreach ($eventSupportedMethods as $method) { // 设置只使用 epoll方式
    if ($method === 'epoll') continue;
    $eventConfig->avoidMethod($method);
}
$eventBase = new EventBase($eventConfig);

$clientSockets = []; // 存储所有 socket
$clientSocketEvents = []; // 存储所有 Event

// 将socket绑定事件
// callback回调 static void event_cb(evutil_socket_t fd, short what, void *arg) 最后一个参数引用 __construct() 的最后一个参数
// public function __construct(EventBase $base, $fd, int $what, callable $cb, $arg = null)
$socketEvent = new Event($eventBase, $streamServerSocket, Event::READ | Event::PERSIST, function ($fd, int $what, EventBase $arg) use (&$clientSockets, &$clientSocketEvents) {
    if ($what !== Event::READ) {
        echo '不是 读事件(有设备连上) !!!';
        return;
    }
    $clientSocket = stream_socket_accept($fd);
    if ($clientSocket === false) {
        echo 'stream_socket_accept() failed !!! ' . PHP_EOL;
        return;
    }
    stream_set_blocking($fd, false);
    //获取客户端IP地址
    echo "client addr: " . stream_socket_get_name($clientSocket, true) . "\n";

    $clientSockets[intval($clientSocket)] = $clientSocket; // 持久化 socket

    $clientSocketEvent = new Event($arg, $clientSocket, Event::READ | Event::PERSIST, function ($fd, $what, $arg) use (&$clientSocketEvent, &$clientSockets, &$clientSocketEvents) {
        if ($what !== Event::READ) {
            echo '不是 读事件(有数据写入、设备断开) !!!';
            return;
        }

        $buff = fread($fd, 1024);
        if ($buff === false || $buff === '') {
            echo "client closed !! " . intval($fd) . PHP_EOL;
            echo "client addr: " . stream_socket_get_name($fd, true) . "\n";
            // 清理、释放资源
            fclose($fd);
            unset($clientSockets[intval($fd)]);
            $clientSocketEvent->del();
            unset($clientSocketEvents[intval($fd)]);
            return;
        }

        echo "recv:" . $buff . "\n";
        fwrite($fd, $buff);
    });

    $clientSocketEvent->add();
    $clientSocketEvents[intval($clientSocket)] = $clientSocketEvent; // 持久化 event
}, $eventBase);

// SIGINT 监听 ctrl + c 信号
$signalEvent = new Event($eventBase, SIGINT, Event::SIGNAL, function () use ($eventBase) {
    echo 'event exit !!' . PHP_EOL;
    $eventBase->exit(0); // ctrl + c 退出事件loop
});

$socketEvent->add();
$signalEvent->add();

// EventBase::LOOP_ONCE         阻塞直到libevent第一个活动事件的回调事件完成,然后在所有活动事件退出
// EventBase::LOOP_NONBLOCK     不要阻塞:查看哪些事件现在已经准备好,运行最高优先级的回调,然后退出
// 0                            根据Event 执行事件
$eventBase->loop(0);
// 没有事件后 退出

fclose($streamServerSocket);
echo 'exit ' . PHP_EOL;

Comments (2)

  1. Log in to comment