前言

PHP本身自带的socket套接字连接一直都是尴尬的存在...从create到bind到listen再到accept一切连接所需要做的事情都得你有亲手去解决,这可是工作量极其繁重的事情,且必须是对各协议的通信过程了解的情况下才能入手,但是如果你拥有了swoole这PHP异步、并行、高性能网络通信引擎的话就一切将会变的更加容易!

以下是我利用swoole轻松构建websocket服务器,以实现一个在线即时聊天室的DEMO.

为什么选择websocket

什么是websocket?这里就不一一细述,想了解的同学可以自行百科,通俗的来讲就是html5新出的通信协议,可以实现browser与server之间的双向通讯。

接下来说说为什么要选择他,相信大家都只要如果在web实现聊天室的功能通常的做法就是利用ajax长轮询定时发起http请求至服务器取得最新数据,这种方式虽然简单但是有很多的缺点,如果只是构造一个10人不等的聊天室肯定不成为问题,但是如果当100人1000人同时发起大量http请求时,这就大大增加了性能消耗,严重浪费服务器资源,为了解决此问题,websocket因此诞生。

CODE

Server

<?php
  //构造一个websocket服务器
  $serv = new swoole_websocket_server('0.0.0.0',9501);

  //定义连接事件
  $serv->on('open',function(swoole_websocket_server $serv,$request){
    echo '客户 '.$request->fd.' 连接服务器'.PHP_EOL;
  });

  //定义消息事件
  $serv->on('message',function(swoole_websocket_server $serv,$request){
    //构造一个memcache对象并连接
    $mem = new Memcached();
    $mem->addServer('127.0.0.1',11211);

    if(($data = json_decode($request->data,true))['action'] == 'add'){
      $mem->set($request->fd,$data['data']);
    }else{
      echo '来自 '.$mem->get($request->fd).' 的信息: '.$request->data.PHP_EOL;
      //取出所有已连接服务器的FD列表
      $clientList = $serv->connection_list();
      //遍历fd列表,单独最每个fd发送message
      foreach ($clientList as $fd) {
          $serv->push($fd,$mem->get($request->fd).':'.$request->data);
      }
    }
  });

  //定义关闭事件
  $serv->on('close',function(swoole_websocket_server $serv,$fd){
    $mem = new Memcached();
    $mem->addServer('127.0.0.1',11211);

    foreach ($serv->connection_list() as $fd) {
      $serv->push($fd,$mem->get($request->fd).' 离开房间.');
    }
  });

  $serv->start();
?>

client

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
    <script src="//cdn.bootcss.com/jquery/3.0.0-beta1/jquery.js"></script>
    <script src="//cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
</head>
<body>
  <div>
    <div id="box" style="width:500px;height:100px;border:1px solid black;overflow:auto;"></div>
    <textarea style="width:400px;heigt:100px;float:left;"></textarea>
    <input type="button" style="padding:10px 32px;float:left;" value="发送"  onclick="ws.send($(this).prev().val())" />
  </div>
</body>
<script type="text/javascript">
  var uname;
  var ws;
  ws = new WebSocket("ws://ubuntu.otokaze.cn:9501");

  ws.onopen = function(){
    if(!$.cookie('uname')){
      uname = (uname = prompt('君の名前は?')) ? uname : '名無し';
      $.cookie('uname',uname);
      ws.send(JSON.stringify({'action':'add','data':uname}));
    }
  };
  ws.onmessage = function (evt){
    $('#box').html($('#box').html()+evt.data+"<br>");
  };

</script>
</html>

效果图


風前の灯になってもいいさ、残したの歳月痕跡を持ち続けて生きてゆく。