PHP Socket 编程提供了两套API:socket_*
系列, 需要安装 socket 扩展(更底层)stream_socket_*
系列, 不需要安装扩展(推荐使用, 更方便)
ps:分别以 socket 扩展 和 stream_socket 实现了服务端与客户端的通信,测试方式一样
socket 扩展 - 服务端与客户端的通信
服务端 server.php
1 |
|
客户端 client.php
1 |
|
测试
1 | #1. 启动服务端 |
问题:只能处理一个客户端的连接和数据传输, 只有断开后才能处理新的客户端连接
解决:IO 复用
IO 复用 - 服务端 server.php
1 |
|
测试
1 | #1. 启动服务端 |
stream_socket - 服务端与客户端的通信
服务端 server.php
1 |
|
客户端 client.php
1 |
|
IO 复用 - 服务端 server.php
1 |
|
相关说明:
- socket_create 创建并返回一个套接字(用于监听[listen]和接受[accept]客户端的连接请求,不能用于与客户端之间发送和接收数据)
- socket_accept 接受一个客户端的连接请求, 并返回一个新的套接字, 这个套接字与socket_create 返回的用于监听和接受客户端的连接请求的套接字不是同一个套接字,与本次接受的客户端的通信是通过在这个新的套接字上发送和接收数据来完成的
- 再次调用 socket_accept 可以接受下一个客户端的连接请求, 并再次返回一个新的套接字(与socket_create 返回的套接字、之前 socket_accept 返回的套接字都不同的新的套接字), 这个新的套接字用于与这次接受的客户端之间的通信
- 假设一共有3个客户端连接到服务器端, 那么在服务器端就一共有4个套接字, 第1个是 socket_create 返回的(用于监听的套接字),其余3个是分别调用3次 socket_accept 返回的不同的套接字
- 如果已经有客户端连接到服务器端, 不再需要监听和接受更多的客户端连接的时候, 可以关闭由 socket_create 返回的套接字, 而不会影响与客户端之间的通信
- 当某个客户端断开连接、或者是与某个客户端的通信完成之后, 服务器端需要关闭用于与该客户端通信的套接字
- socket_listen 说明:每个 connect 都是往 listen 队列填装连接, 每一个 accept 操作都会从 listen 队列取连接转成 socket, 等待这个socket close 掉之后再继续从 listen 队列中取连接, 而 listen 队列长度就是 socket_listen 函数的第二个参数 backlog
- socket_select 接受三个套接字数组, 分别检查数组中的套接字是否处于可以操作的状态(返回时只保留可操作的套接字), 使用最多的是 $read, 因此以读为例.
在套接字数组 $read 中最初应保有一个服务端监听套接字, 每当该套接字可读时, 就表示有一个用户发起了连接, 此时你需要对该连接创建一个套接字, 并加入到 $read 数组中;
当然, 并不只是服务端监听的套接字会变成可读的, 用户套接字也会变成可读的, 此时你就可以读取用户发来的数据了;
socket_select只在套接字数组发生了变化时才返回
, 也就是说, 一旦执行到 socket_select 的下一条语句, 则必有一个套接字是需要你操作的 - stream_socket_server($local_socket, $errno, $errstr, STREAM_SERVER_BIND | STREAM_SERVER_LISTEN) 相当于 socket_create()、socket_bind()、socket_listen()
- stream_socket_accept 第二个参数
$timeout
, 设置为0
, 连接将立即超时, 设置为-1
, 无限期等待连接 - stream_select 与 socket_select 用法相似