IT俱乐部 PHP Swoole 4.x服务器Server配置和函数列表

Swoole 4.x服务器Server配置和函数列表

简介

Swoole 是一个使用 C++ 语言编写的基于异步事件驱动和协程的并行网络通信引擎,为 PHP 提供协程、高性能网络编程支持。提供了多种通信协议的网络服务器和客户端模块,可以方便快速的实现 TCP/UDP服务、高性能Web、WebSocket服务、物联网、实时通讯、游戏、微服务等,使 PHP 不再局限于传统的 Web 领域。

PHP的异步、并行、高性能网络通信引擎,使用纯C语言编写,提供了多种通信协议的异步IO服务器和客户端。Swoole4 支持了完整的 Coroutine + Channel CSP 编程模式 ,可以使用同步风格实现异步程序。

预定义常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
// 预定义常量
SWOOLE_VERSION 当前Swoole的版本号,字符串类型,如1.6.0
 
// swoole_server构造函数参数
SWOOLE_BASE 使用Base模式,业务代码在Reactor进程中直接执行
SWOOLE_PROCESS 使用进程模式,业务代码在Worker进程中执行
 
// swoole_client构造函数参数
SWOOLE_SOCK_TCP 创建tcp socket
SWOOLE_SOCK_TCP6 创建tcp ipv6 socket
SWOOLE_SOCK_UDP 创建udp socket
SWOOLE_SOCK_UDP6 创建udp ipv6 socket
SWOOLE_SOCK_SYNC 同步客户端
SWOOLE_SOCK_ASYNC 异步客户端
 
// swoole_lock构造函数参数
SWOOLE_FILELOCK 创建文件锁
SWOOLE_MUTEX 创建互斥锁
SWOOLE_RWLOCK 创建读写锁
SWOOLE_SPINLOCK 创建自旋锁
SWOOLE_SEM 创建信号量
 
// SSL加密方法
SWOOLE_SSLv3_SERVER_METHOD;
SWOOLE_SSLv3_METHOD;
SWOOLE_SSLv3_CLIENT_METHOD;
SWOOLE_SSLv23_METHOD 默认加密方法;
SWOOLE_SSLv23_SERVER_METHOD;
SWOOLE_SSLv23_CLIENT_METHOD;
SWOOLE_TLSv1_METHOD;
SWOOLE_TLSv1_SERVER_METHOD;
SWOOLE_TLSv1_CLIENT_METHOD;
SWOOLE_TLSv1_1_METHOD;
SWOOLE_TLSv1_1_SERVER_METHOD;
SWOOLE_TLSv1_1_CLIENT_METHOD;
SWOOLE_TLSv1_2_METHOD;
SWOOLE_TLSv1_2_SERVER_METHOD;
SWOOLE_TLSv1_2_CLIENT_METHOD;
SWOOLE_DTLSv1_METHOD;
SWOOLE_DTLSv1_SERVER_METHOD;
SWOOLE_DTLSv1_CLIENT_METHOD;

 

Server 配置选项

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
$serv->set(array(
// 通过此参数来调节主进程内事件处理线程的数量,以充分利用多核。默认会启用CPU核数相同的数量。一般设置为CPU核数的1-4倍
 'reactor_num' => 2,
 
// 设置启动的Worker进程数。业务代码是全异步非阻塞的,这里设置为CPU的1-4倍最合理
 // 业务代码为同步阻塞,需要根据请求响应时间和系统负载来调整
 'worker_num' => 2,
 
// 设置worker进程的最大任务数,默认为0,一个worker进程在处理完超过此数值的任务后将自动退出,进程退出后会释放所有内存和资源。
 'max_request' => 1000,
 
// 服务器程序,最大允许的连接数, 此参数用来设置Server最大允许维持多少个TCP连接。超过此数量后,新进入的连接将被拒绝
 'max_connection' => 10000,
 
// 配置Task进程的数量,配置此参数后将会启用task功能。所以Server务必要注册onTask
 'task_worker_num' => 2,
 
// 设置Task进程与Worker进程之间通信的方式。1使用unix socket通信,默认模式, 2使用消息队列通信, 3使用消息队列通信,并设置为争抢模式
 'task_ipc_mode' => 1
 
// 设置task进程的最大任务数。一个task进程在处理完超过此数值的任务后将自动退出。
 'task_max_request'         => 0,
 
// 设置task的数据临时目录,在swoole_server中,如果投递的数据超过8192字节,将启用临时文件来保存数据
 'task_tmpdir'              => '/tmp',
 
// 数据包分发策略默认为2。1轮循模式,2固定模式,3抢占模式,4IP分配,5UID分配
 'dispatch_mode'            => 2,
 
// 设置dispatch函数,swoole底层了内置了5种dispatch_mode,如果仍然无法满足需求。
 // 可以使用编写C++函数或PHP函数,实现dispatch逻辑。使用方法:
 'dispatch_func' => 'my_dispatch_function',
 
// 设置消息队列的KEY,仅在task_ipc_mode = 2/3时使用。
 // 设置的Key仅作为Task任务队列的KEY,此参数的默认值为ftok($php_script_file, 1)
 'message_queue_key'        => ftok(SYS_ROOT . 'queue.msg', 1),
 
//  设置守护进程模式
 'daemonize'                => 1,
 
// Listen队列长度,如backlog => 128,此参数将决定最多同时有多少个等待accept的连接
 'backlog'                  => 128,
 
// 指定swoole错误日志文件。在swoole运行期发生的异常信息会记录到这个文件中。默认会打印到屏幕
 'log_file'                 => '/data/logs/swoole.log',
 
// 设置swoole_server错误日志打印的等级,范围是0-5。低于log_level设置的日志信息不会抛出
 'log_level' => 1,
 
// 启用心跳检测,此选项表示每隔多久轮循一次,单位为秒
 'heartbeat_check_interval' => 10,
 
// 与heartbeat_check_interval配合使用。表示连接最大允许空闲的时间
 'heartbeat_idle_time'      => 20,
 
// 打开EOF检测,此选项将检测客户端连接发来的数据,当数据包结尾是指定的字符串时才会投递给Worker进程
 // 否则会一直拼接数据包,直到超过缓存区或者超时才会中止。当出错时底层会认为是恶意连接,丢弃数据并强制关闭连接
 'open_eof_check' => true,
 
// 启用EOF自动分包。当设置open_eof_check后,底层检测数据是否以特定的字符串结尾来进行数据缓冲
 'open_eof_split' => true,
 
// 与 open_eof_check 或者 open_eof_split 配合使用,设置EOF字符串。
 'package_eof'              => "rrn",
 
// 打开包长检测特性。包长检测提供了固定包头+包体这种格式协议的解析。
 // 启用后,可以保证Worker进程onReceive每次都会收到一个完整的数据包。
 'open_length_check' => true,
 
// 长度值的类型,接受一个字符参数,与php的 pack 函数一致。
 'package_length_type'   => 'N',
 
// 设置长度解析函数,支持C++或PHP的2种类型的函数。长度函数必须返回一个整数
 'package_length_func' => 'package_length_func_name'
 
// 设置最大数据包尺寸,单位为字节
 'package_max_length' => 2000000,
 
// 启用CPU亲和性设置
 'open_cpu_affinity'        => 1,
 
// cpu_affinity_ignore 设置将此CPU空出,专门用于处理网络中断
 'cpu_affinity_ignore' => [0,1],
 
// 启用open_tcp_nodelay,开启后TCP连接发送数据时会关闭Nagle合并算法,立即发往客户端连接
 'open_tcp_nodelay' => 1,
 
// 启用tcp_defer_accept特性,可以设置为一个数值,表示当一个TCP连接有数据发送时才触发accept
 'tcp_defer_accept' => 5
 
// 设置SSL隧道加密,设置值为一个文件名字符串,制定cert证书和key私钥的路径
 'ssl_cert_file' => __DIR__.'/config/ssl.crt',
'ssl_key_file' => __DIR__.'/config/ssl.key',
 
// 设置OpenSSL隧道加密的算法。Server与Client使用的算法必须一致,否则SSL/TLS握手会失败,连接会被切断
 'ssl_method' => SWOOLE_SSLv3_CLIENT_METHOD,
 
// 启用SSL后,设置ssl_ciphers来改变openssl默认的加密算法
 'ssl_ciphers' => 'ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP',
 
// 设置worker/task子进程的所属用户
 'user' => 'swoole',
 
// 设置worker/task子进程的进程用户组
 'group' => 'www-data',
 
// 重定向Worker进程的文件系统根目录
 'chroot' => '/data/server/',
 
// 在Server启动时自动将master进程的PID写入到文件,在Server关闭时自动删除PID文件
 'pid_file' => __DIR__.'/server.pid',
 
// 调整管道通信的内存缓存区长度。Swoole使用Unix Socket实现进程间通信。
 'pipe_buffer_size' => 32 * 1024 *1024,
 
// 配置发送输出缓存区内存尺寸
 'buffer_output_size' => 32 * 1024 *1024
 
// 配置客户端连接的缓存区长度
 'socket_buffer_size' => 128 * 1024 *1024
 
// swoole在配置dispatch_mode=1或3后,因为系统无法保证onConnect/onReceive/onClose的顺序,默认关闭了onConnect/onClose事件。
 // 如果应用程序需要onConnect/onClose事件,并且能接受顺序问题可能带来的安全风险,
 // 可以通过设置enable_unsafe_event为true,启用onConnect/onClose事件
 'enable_unsafe_event' => true,
 
 
// swoole在配置dispatch_mode=1或3后,系统无法保证onConnect/onReceive/onClose的顺序,因此可能会有一些请求数据在连接关闭后,
 // 才能到达Worker进程。discard_timeout_request配置默认为true,表示如果worker进程收到了已关闭连接的数据请求,将自动丢弃。
 // discard_timeout_request如果设置为false,表示无论连接是否关闭Worker进程都会处理数据请求。
 'discard_timeout_request' => true,
 
// 设置端口重用
 'enable_reuse_port' => true,
 
// 设置此选项为true后,accept客户端连接后将不会自动加入EventLoop,仅触发onConnect回调。
 // worker进程可以调用$serv->confirm($fd)对连接进行确认,此时才会将fd加入EventLoop开始进行数据收发,
 // 也可以调用$serv->close($fd)关闭此连接。
 'enable_delay_receive' => true,
 
// 启用Http协议处理
 'open_http_protocol' => true,
 
// 启用HTTP2协议解析,需要依赖--enable-http2编译选项。默认为false
 'open_http2_protocol' => true,
 
// 启用websocket协议处理,SwooleWebSocketServer会自动启用此选项
 'open_websocket_protocol' => true,
 
// 启用mqtt协议处理,启用后会解析mqtt包头,worker进程onReceive每次会返回一个完整的mqtt数据包
 'open_mqtt_protocol' => true,
 
// 设置异步重启开关
 'reload_async' => true,
 
// 开启TCP快速握手特性。此项特性,可以提升TCP短连接的响应速度,在客户端完成握手的第三步,发送SYN包时携带数据
 'tcp_fastopen' => true
 
// 开启请求慢日志。启用后Manager进程会设置一个时钟信号,定时侦测所有Task和Worker进程,
 // 一旦进程阻塞导致请求超过规定的时间,将自动打印进程的PHP函数调用栈
 'request_slowlog_file' => '/tmp/trace.log',
 
// enable_coroutine参数,默认为true,通过设置为false可关闭内置协程
 'enable_coroutine' => false
 
// 设置当前工作进程最大协程数量,超过max_coroutine底层将无法创建新的协程,底层会抛出错误,并直接关闭连接
 'max_coroutine' => 3000,
));

Server 函数列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// 创建一个异步Server对象。
$serv = new swoole_server('0.0.0.0', '9501', $mode = SWOOLE_PROCESS, $sock_type = SWOOLE_SOCK_TCP);
 
// swoole_server->set函数用于设置swoole_server运行时的各项参数。
 // 服务器启动后通过$serv->setting来访问set函数设置的参数数组。
$serv->set(array(
    'reactor_num' => 2,
    'worker_num' => 4,
    'backlog' => 128,
    'max_request' => 50,
    'dispatch_mode' => 1,
));
 
// 注册Server的事件回调函数。
$serv->on('connect', function ($serv, $fd){
    echo "Client:Connect.n";
});
 
// 增加监听的端口。业务代码中可以通过调用swoole_server::connection_info来获取某个连接来自于哪个端口。
$serv->addlistener("127.0.0.1", 9502, SWOOLE_SOCK_TCP);
// 监听一个新的Server端口,此方法是addlistener的别名
$serv->listen("127.0.0.1", 9503, SWOOLE_SOCK_TCP);
 
// 添加一个用户自定义的工作进程。此函数通常用于创建一个特殊的工作进程,用于监控、上报或者其他特殊的任务。
$process = new swoole_process(function($process) use ($server) {
    while (true) {
        $msg = $process->read();
        foreach($server->connections as $conn) {
            $server->send($conn, $msg);
        }
    }
});
$server->addProcess($process);
 
// 启动server,监听所有TCP/UDP端口
$serv->start();
 
// 重启所有worker进程。$only_reload_taskworkrer 是否仅重启task进程
$serv->reload($only_reload_taskworkrer = false);
 
// 使当前worker进程停止运行,并立即触发onWorkerStop回调函数。
swoole_server->stop(int $worker_id = -1, bool $waitEvent = false);
 
// 此函数可以用在worker进程内。向主进程发送SIGTERM也可以实现关闭服务器。
$serv->shutdown();
 
// tick定时器,可以自定义回调函数。此函数是swoole_timer_tick的别名。
$serv->tick(1000, function ($id) {
    var_dump($id);
});
 
// 在指定的时间后执行函数,swoole_server::after函数是一个一次性定时器,执行完成后就会销毁
$serv->after(2000, function(){
    echo "Timeout: ".microtime(true)."n";
});
 
// 延后执行一个PHP函数。Swoole底层会在EventLoop循环完成后执行此函数。
 // 此函数的目的是为了让一些PHP代码延后执行,程序优先处理IO事件。
$server->defer(function() use ($db) {
    $db->close();
});
 
// 清除tick/after定时器,此函数是 swoole_timer_clear 的别名。
$timer_id = $server->tick(1000, function ($id) use ($server) {
    $server->clearTimer($id);
});
 
// 关闭客户端连接,操作成功返回true,失败返回false.
$serv->close($fd);
 
// 向客户端发送数据 $data,发送的数据,TCP协议最大不得超过2M,可修改 buffer_output_size 改变允许发送的最大包长度
 // UDP协议不得超过65507,UDP包头占8字节, IP包头占20字节,65535-28 = 65507
$serv->send($fd, 'Swoole: '.$data);
 
// 发送文件到TCP客户端连接
$serv->sendfile($fd, __DIR__.'/test.jpg');
 
// 向任意的客户端IP:PORT发送UDP数据包
$serv->sendto("127.0.0.1", 9999, "hello world");
 
// 阻塞地向客户端发送数据
server->sendwait($fd, "hello world");
 
// 此函数可以向任意worker进程或者task进程发送消息。在非主进程和管理进程中可调用。收到消息的进程会触发onPipeMessage事件
$serv->sendMessage("hello task process", $worker_id);
 
// 检测fd对应的连接是否存在,$fd对应的TCP连接存在返回true,不存在返回false
$serv->exist($fd)
 
// 停止接收数据。调用此函数后会将连接从EventLoop中移除,不再接收客户端数据
$serv->pause($fd)
 
// 恢复数据接收。与pause方法成对使用,调用此函数后会将连接重新加入到EventLoop中,继续接收客户端数据
$serv->resume(int $fd);
 
// swoole_server->getClientInfo函数用来获取连接的信息,别名是swoole_server->connection_info
$fdinfo = $serv->connection_info($fd);
 
// 用来遍历当前Server所有的客户端连接,方法是基于共享内存的,不存在IOWait
 // 推荐使用 swoole_server::$connections 迭代器来遍历连接,getClientList的别名是connection_list
$conn_list = $serv->getClientList($start_fd, 10);
 
// 将连接绑定一个用户定义的UID,可以设置dispatch_mode=5设置以此值进行hash固定分配。
 // 可以保证某一个UID的连接全部会分配到同一个Worker进程。
$serv->bind($fd, $uid)
 
// 得到当前Server的活动TCP连接数,启动时间,accpet/close的总次数等信息。
$serv_stats = $serv->stats();
 
// 投递一个异步任务到task_worker池中。此函数是非阻塞的,执行完毕会立即返回。Worker进程可以继续处理新的请求。
 // 使用Task功能,必须先设置 task_worker_num,并且必须设置Server的onTask和onFinish事件回调函数
$task_id = $serv->task("some data");
 
// taskwait与task方法作用相同,用于投递一个异步的任务到task进程池去执行。
 // 与task不同的是taskwait是同步等待的,直到任务完成或者超时返回。
$serv->taskwait(['type' => 'array', 'value' => $data]);
 
// 并发执行多个Task,$tasks 必须为数字索引数组,不支持关联索引数组
$tasks[] = mt_rand(1000, 9999);
// 任务1
$tasks[] = mt_rand(1000, 9999);
// 任务2
var_dump($tasks);
// 等待所有Task结果返回,超时为10s
$results = $serv->taskWaitMulti($tasks, 10.0);
 
// 并发执行Task并进行协程调度
$result = $serv->taskCo($tasks, 0.5);
 
// 此函数用于在task进程中通知worker进程,投递的任务已完成。此函数可以传递结果数据给worker进程。
$serv->finish("response");
 
// 检测服务器所有连接,并找出已经超过约定时间的连接。
 // 如果指定if_close_connection,则自动关闭超时的连接。未指定仅返回连接的fd数组。
$closeFdArr = $serv->heartbeat();
 
// 获取最近一次操作错误的错误码。业务代码中可以根据错误码类型执行不同的逻辑。
$errCode = $serv->getLastError();
 
// 调用此方法可以得到底层的socket句柄,返回的对象为sockets资源句柄。
 // 依赖PHP的sockets扩展,并且编译swoole时需要开启--enable-sockets选项
$socket = $serv->getSocket();
 
// 设置客户端连接为保护状态,不被心跳线程切断。
$serv->protect(int $fd, bool $value = 1);
 
// 确认连接,与enable_delay_receive或wait_for_bind配合使用。当客户端建立连接后,并不监听可读事件。
 // 仅触发onConnect事件回调在onConnect回调中执行confirm确认连接,这时服务器才会监听可读事件,接收来自客户端连接的数据。
$serv->confirm(int $fd);

Server 属性列表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// swoole_server::set()函数所设置的参数会保存到swoole_server::$setting属性上。在回调函数中可以访问运行参数的值。
echo $serv->setting['worker_num'];
 
// 返回当前服务器主进程的PID。
 int $serv->master_pid;
 
// 返回当前服务器管理进程的PID。
 int $serv->manager_pid;
 
// 得到当前Worker进程的编号,包括Task进程。Worker进程编号范围是[0, worker_num]
 // Task进程编号范围是[worker_num, worker_num + task_worker_num]
 int $serv->worker_id;
 
// 得到当前Worker进程的操作系统进程ID。与posix_getpid()的返回值相同。
 int $serv->worker_pid;
 
// 布尔类型,true表示当前的进程是Task工作进程,false表示当前的进程是Worker进程
 bool $serv->taskworker;
 
// TCP连接迭代器,可以使用foreach遍历服务器当前所有的连接,
 // 此属性的功能与swoole_server->connnection_list是一致的,但是更加友好。遍历的元素为单个连接的fd。
 // 监听端口数组,如果服务器监听了多个端口可以遍历swoole_server::$ports得到所有SwooleServerPort对象。
 // 其中swoole_server::$ports[0]为构造方法所设置的主服务器端口。
$ports = swoole_server::$ports;
$ports[0]->set($settings);
$ports[1]->on("Receive", function(){});

事件回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
// Server启动在主进程的主线程回调此函数
$serv->on('Start', function(SwooleServer $server){});
 
// 此事件在Server正常结束时发生
$serv->on('Shutdown', function(SwooleServer $server){});
 
// 此事件在Worker进程/Task进程启动时发生
$serv->on('WorkerStart', function(SwooleServer $server, int $worker_id){});
 
// 此事件在worker进程终止时发生
$serv->on('WorkerStop', function(SwooleServer $server, int $worker_id){});
 
// 仅在开启reload_async特性后有效会先创建新的Worker进程处理新请求,旧的Worker进程自行退出。
$serv->on('WorkerExit', function(SwooleServer $server, int $worker_id){});
 
// 有新的连接进入时,在worker进程中回调
$serv->on('Connect', function(SwooleServer $server, int $fd, int $reactorId){});
 
// 接收到数据时回调此函数,发生在worker进程中
$serv->on('Receive', function(SwooleServer $server, int $fd, int $reactor_id, string $data){});
 
// 接收到UDP数据包时回调此函数,发生在worker进程中
$serv->on('Packet', function(SwooleServer $server, string $data, array $client_info){});
 
// TCP客户端连接关闭后,在worker进程中回调此函数
$serv->on('Close', function(SwooleServer $server, int $fd, int $reactorId){});
 
// 当缓存区达到最高水位时触发此事件。
$serv->on('BufferFull', function(SwooleServer $serv, int $fd){});
 
// 当缓存区低于最低水位线时触发此事件
$serv->on('BufferEmpty', function(SwooleServer $serv, int $fd){});
 
// 在task_worker进程内被调用。worker进程可以使用swoole_server_task函数向task_worker进程投递新的任务。
 // 当前的Task进程在调用onTask回调函数时会将进程状态切换为忙碌,这时将不再接收新的Task,
 // 当onTask函数返回时会将进程状态切换为空闲然后继续接收新的Task。
$serv->on('Task', function(SwooleServer $serv, int $task_id, int $src_worker_id, mixed $data){});
 
// 当worker进程投递的任务在task_worker中完成时,
 // task进程会通过swoole_server->finish()方法将任务处理的结果发送给worker进程
$serv->on('Finish', function(SwooleServer $serv, int $task_id, string $data){});
 
// 当工作进程收到由 sendMessage 发送的管道消息时会触发onPipeMessage事件。worker/task进程都可能会触发onPipeMessage事件
$serv->on('PipeMessage', function(SwooleServer $server, int $src_worker_id, mixed $message){});
 
// 当worker/task_worker进程发生异常后会在Manager进程内回调此函数
$serv->on('WorkerError', function(SwooleServer $serv, int $worker_id, int $worker_pid, int $exit_code, int $signal){});
 
// 当管理进程启动时调用它
$serv->on('ManagerStart', function(SwooleServer $serv){});
 
// 当管理进程结束时调用它
$serv->on('ManagerStop', function(SwooleServer $serv){});
本文收集自网络,不代表IT俱乐部立场,转载请注明出处。https://www.2it.club/code/php/14234.html
上一篇
下一篇
联系我们

联系我们

在线咨询: QQ交谈

邮箱: 1120393934@qq.com

工作时间:周一至周五,9:00-17:30,节假日休息

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部