这个列子主要讨论Tcp,WebSocket和http之间的通讯。长连接和长连接通讯,长连接和短连接通讯。其他协议同理可得Tcp: 代表硬件设备WebSocket: 代表客户端 http: 代表网页 本列子是基于one框架 (https://github.com/lizhichao/one) 开发.配置协议 监听端口由于swoole的模型 WebSocket server 包含 http server , http server 包含 tcp server 。所以我们配置主服务为 WebSocket server ,添加两个http 和 tcp 监听。配置文件如下:return [ ‘server’ => [ ‘server_type’ => \One\Swoole\OneServer::SWOOLE_WEBSOCKET_SERVER, ‘port’ => 8082, ‘action’ => \App\Test\MixPro\Ws::class, ‘mode’ => SWOOLE_PROCESS, ‘sock_type’ => SWOOLE_SOCK_TCP, ‘ip’ => ‘0.0.0.0’, ‘set’ => [ ‘worker_num’ => 5 ] ], ‘add_listener’ => [ // http 监听 [ ‘port’ => 8081, ‘action’ => \App\Server\AppHttpPort::class, ’type’ => SWOOLE_SOCK_TCP, ‘ip’ => ‘0.0.0.0’, ‘set’ => [ ‘open_http_protocol’ => true, ‘open_websocket_protocol’ => false ] ], // tcp 监听 [ ‘port’ => 8083, ‘pack_protocol’ => \One\Protocol\Text::class, // tcp 打包,解包协议,方便在终端调试 我们使用 text 协议. 换行符 表示一个包的结束 ‘action’ => \App\Test\MixPro\TcpPort::class, ’type’ => SWOOLE_SOCK_TCP, ‘ip’ => ‘0.0.0.0’, ‘set’ => [ ‘open_http_protocol’ => false, ‘open_websocket_protocol’ => false ] ] ]];接下来去 \App\Test\MixPro\Ws 和 \App\Test\MixPro\TcpPort 实现各种事件处理。\App\Server\AppHttpPort 是框架内置的,通过路由处理http请求的,配置路由即可。配置路由// 首页Router::get(’/mix’, [ ‘use’ => HttpController::class . ‘@index’, ‘middle’ => [\App\Test\MixPro\TestMiddle::class . ‘@isLogin’] // 中间件 如果用户登录了 直接跳转到相应的页面]);Router::group([ ‘middle’ => [\App\Test\MixPro\TestMiddle::class . ‘@checkSession’] // 中间件 让用户登录后 才能进入聊天页面 http websocket 都能获取到这个 session ], function () { // websocket 页面 Router::get(’/mix/ws’, HttpController::class . ‘@ws’); // http 页面 Router::get(’/mix/http’, HttpController::class . ‘@http’); // http 轮训消息接口 Router::post(’/mix/http/loop’, HttpController::class . ‘@httpLoop’); // http 发送消息接口 Router::post(’/mix/http/send’, HttpController::class . ‘@httpSend’);});配置的都是 http 协议路由。 websocket和tpc我们直接在回调action处理。如果你的项目复杂也可以配置相应的路由。one框架的路由支持任何协议,使用方法也是统一的。处理tcp协议其中__construct,onConnect,onClose 不是必须的。 如果你想在服务器运行开始时最一些事情就写到 __construct里面。 onConnect 当有客户端连接时触发,每个客户端触发一次 onClose 当有客户端连接断开时触发,每个客户端触发一次class TcpPort extends Tcp{ use Funs; private $users = []; /** * @var Ws / protected $server; /* * @var Client / protected $global_data; public function __construct($server, $conf) { parent::__construct($server, $conf); $this->global_data = $this->server->global_data; } // 终端连接上服务器时 public function onConnect(\swoole_server $server, $fd, $reactor_id) { $name = uuid(); $this->users[$fd] = $name; $this->sendTo(‘all’, json_encode([‘v’ => 1, ’n’ => $name])); $this->sendToTcp($fd, json_encode([‘v’ => 4, ’n’ => $this->getAllName()])); $this->global_data->bindId($fd, $name); $this->send($fd, “你的名字是:” . $name); } // 消息处理 像某个name 发送消息 public function onReceive(\swoole_server $server, $fd, $reactor_id, $data) { $arr = explode(’ ‘, $data); if (count($arr) !== 3 || $arr[0] !== ‘send’) { $this->send($fd, “格式不正确”); return false; } $n = $arr[1]; $d = $arr[2]; $this->sendTo($n, json_encode([‘v’ => 3, ’n’ => $d])); } // 下线 通知所有其他终端,解除与fd的关系绑定。 public function onClose(\swoole_server $server, $fd, $reactor_id) { echo “tcp close {$fd} \n”; $this->global_data->unBindFd($fd); $this->sendTo(‘all’, json_encode([‘v’ => 2, ’n’ => $this->users[$fd]])); unset($this->users[$fd]); }}定义了一个公共的traitFuns主要实现两个方法,获取所有的终端(tcp,ws,http),和向某个用户发送消息 。在ws、http都会用到这个 在构造函数我们初始化了一个 global_data 用来保存,名称和fd的关系。你也可以使用方式储存。因为fd没次连接都不同。global_data是one框架内置的。 终端连接上服务器时触发事件 onConnect ,我们给这个终端取个名字,并把关系保存在 global_data。 通知所有终端有个新终端加入,并告诉刚加入的终端当前有哪些终端在线。处理 websocket 协议其中__construct,onHandShake,onOpen,onClose 不是必须的。onHandShake,onOpen 是配合使用的,如果onOpen返回false服务器会拒绝连接。在 onOpen,onMessage,onClose可以拿到当前用户的session信息和http是相通的。class Ws extends WsServer{ use Funs; private $users = []; /* * @var Client / public $global_data = null; public function __construct(\swoole_server $server, array $conf) { parent::__construct($server, $conf); $this->global_data = new Client(); } // 初始化session public function onHandShake(\swoole_http_request $request, \swoole_http_response $response) { return parent::onHandShake($request, $response); } // ws 发送消息 public function onMessage(\swoole_websocket_server $server, \swoole_websocket_frame $frame) { $data = $frame->data; $arr = json_decode($data, true); $n = $arr[’n’]; $d = $arr[’d’]; $this->sendTo($n, json_encode([‘v’ => 3, ’n’ => $d])); } // 判断用户是否登录 如果没有登录拒绝连接 public function onOpen(\swoole_websocket_server $server, \swoole_http_request $request) { $name = $this->session[$request->fd]->get(’name’); if ($name) { $this->users[$request->fd] = $name; $this->sendTo(‘all’, json_encode([‘v’ => 1, ’n’ => $name])); $this->global_data->bindId($request->fd, $name); return true; } else { return false; } } // ws 断开清除信息 public function onClose(\swoole_server $server, $fd, $reactor_id) { echo “ws close {$fd} \n”; $this->global_data->unBindFd($fd); $this->sendTo(‘all’, json_encode([‘v’ => 2, ’n’ => $this->users[$fd]])); unset($this->users[$fd]); }}处理 http 协议主要是 httpLoop 方法,轮训获取消息。因为http是短连接,发给http的信息我们是先存放在$global_data,然后直接这里读取。防止连接间隙丢信息。class HttpController extends Controller{ use Funs; /* * @var Ws / protected $server; /* * @var Client / protected $global_data; public function __construct($request, $response, $server = null) { parent::__construct($request, $response, $server); $this->global_data = $this->server->global_data; } /* * 首页 / public function index() { $code = sha1(uuid()); $this->session()->set(‘code’, $code); return $this->display(‘index’, [‘code’ => $code]); } /* * ws页面 / public function ws() { $name = $this->session()->get(’name’); if (!$name) { $name = uuid(); $this->session()->set(’name’, $name); } return $this->display(‘ws’,[‘users’ => $this->getAllName(),’name’ => $name]); } /* * http 页面 / public function http() { $name = $this->session()->get(’name’); if (!$name) { $name = uuid(); $this->session()->set(’name’, $name); } $this->global_data->set(“http.{$name}”, 1, time() + 60); $this->sendTo(‘all’, json_encode([‘v’ => 1, ’n’ => $name])); return $this->display(‘http’, [’list’ => $this->getAllName(), ’name’ => $name]); } /* * http轮训 / public function httpLoop() { $name = $this->session()->get(’name’); $this->global_data->set(“http.{$name}”, 1, time() + 60); $i = 0; do { $data = $this->global_data->getAndDel(“data.{$name}”); $i++; \co::sleep(0.1); } while ($data === null && $i < 300); if ($data) { foreach ($data as &$v) { $v = json_decode($v, true); } } else { $data = []; } return $this->json($data); } /* * http发送消息 */ public function httpSend() { $n = $this->request->post(’n’); $d = $this->request->post(’d’); if ($n && $d) { $this->sendTo($n, json_encode([‘v’ => 3, ’n’ => $d])); return ‘1’; } return ‘0’; } public function __destruct() { } public function __call($name, $arguments) { return $this->server->$name(…$arguments); }}到此基本就完成了。你可以去看完整的代码 : 点这里 其他的一些列子 : https://github.com/lizhichao/…