• 1
  • 2
  • 3
  • 4
  • 5
阿里云应用开发 首 页  »  帮助中心  »  云服务器  »  阿里云应用开发
五分钟教你写超简单的swoole聊天室
发布日期:2016-7-10 9:7:34

  swoole-1.7.9 增加了内置的websocket服务器支持,通过几行PHP代码即可写出一个异步非阻塞多进程的WebSocket服务器。

  swoole_websocket_server 继承自 swoole_http_server,若设置了onRequest回调,websocket服务器(如阿里云服务器)也可同时作为http服务器。

  $server = new swoole_websocket_server("0.0.0.0", 9501);

  $server->on('open', function (swoole_websocket_server $server, $request) {

  echo "server: handshake success with fd{$request->fd}\n";

  });

  $server->on('message', function (swoole_websocket_server $server, $frame) {

  echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";

  $server->push($frame->fd, "this is server");

  });

  $server->on('close', function ($ser, $fd) {

  echo "client {$fd} closed\n";

  });

  $server->start();

  

  //官网demo

  $server = new swoole_websocket_server("0.0.0.0", 9501);

  $server->on('open', function (swoole_websocket_server $server, $request) {

  echo "server: handshake success with fd{$request->fd}\n";//$request->fd 是客户端id

  });

  $server->on('message', function (swoole_websocket_server $server, $frame) {

  echo "receive from {$frame->fd}:{$frame->data},opcode:{$frame->opcode},fin:{$frame->finish}\n";

  $server->push($frame->fd, "this is server");//$frame->fd 是客户端id,$frame->data是客户端发送的数据

  //服务端向客户端发送数据是用 $server->push( '客户端id' , '内容')

  });

  $server->on('close', function ($ser, $fd) {

  echo "client {$fd} closed\n";

  });

  $server->start();

  我就是喜欢这种简单易懂的demo ,每行代码意思一看就明白

  服务端有了,我找点客户端的js代码

  火狐的MDN

  

  

  

  

  

  

  

  

  

  

  

  

  最后命令行运行php文件,之后浏览器打开html文件,

  F12打开调试界面看console,ok , 没有问题

  此时候我突然想到一个事情,由于我做多进程的那个教程里,在主进程中会将所有的子进程的句柄存起来,以后进行进程间通讯用。那么我将所有的客户端的链接存起来存成数组,每当一个客户端发送消息的时候,我就遍历这个客户端数组,将消息群发一遍,不久实现了聊天室了吗?

  然后就,服务端代码成了这个样子:

  

  $map = array();//客户端集合

  $server = new swoole_websocket_server("0.0.0.0", 9501);

  $server->on('open', function (swoole_websocket_server $server, $request) {

  global $map;//客户端集合

  $map[$request->fd] = $request->fd;//首次连上时存起来

  });

  $server->on('message', function (swoole_websocket_server $server, $frame) {

  global $map;//客户端集合

  $data = $frame->data;

  foreach($map as $fd){

  $server->push($fd , $data);//循环广播

  }

  });

  $server->on('close', function ($ser, $fd) {

  echo "client {$fd} closed\n";

  });

  $server->start();

  大家可以自己试试,运行php后 , 浏览器打开两个页面,看看console.log的内容是什么,

  运行良好,可是并没有实现我们说的那种聊天效果。

  找找原因吧。

  我第一反映看看$map里面是什么,就输出看看,结果发现这个map里面只有一个元素。唉,不对啊,我这是全局变量,难道不应该是有几个客户端链接,就有几个元素吗?这是怎么回事啊,竟然没有保存到所有客户端id?到了这一步,我解决不了map变量的这个问题了,然后我就想看看那个fd是什么东西,老规矩 var_dump输出 , 发现fd就是 int类型的数字,并且是自增的。

  这好办了,不就是数字嘛。

  变量存不了,我搞不定,我存文本里嘛。

  最终版 websocket.php

  

  $server = new swoole_websocket_server("0.0.0.0", 9501);

  $server->on('open', function (swoole_websocket_server $server, $request) {

  file_put_contents( __DIR__ .'/log.txt' , $request->fd);

  });

  $server->on('message', function (swoole_websocket_server $server, $frame) {

  global $client;

  $data = $frame->data;

  $m = file_get_contents( __DIR__ .'/log.txt');

  for ($i=1 ; $i<= $m ; $i++) {

  echo PHP_EOL . ' i is ' . $i . ' data is '.$data . ' m = ' . $m;

  $server->push($i, $data );

  }

  });

  $server->on('close', function ($ser, $fd) {

  echo "client {$fd} closed\n";

  });

  $server->start();

  再次打开html文件,多个页面进行输入观察就可以了。