Table of Contents

上一個主題

中文分詞

下一個主題

CDN

本頁

Channel?

服務概述?

channel是新浪云提供的實時消息推送服務。通過在瀏覽器和新浪云服務端之間建立長連接,使得應用可以方便的向javascript客戶端實時的推送消息。

下圖為channel服務的大致使用流程:

../../_images/channel-overview.png

channel服務的使用主要包含兩個部分:JS客戶端,服務端處理程序。

對于JS客戶端,其需要完成:

  • 使用應用服務端創建的channel url連接上channel的服務器。
  • 設置下行消息的處理函數。
  • 需要發送消息時,調用send發送消息給channel服務器(或者直接使用XMLHttpRequest直接發送給應用服務端也可)。

對于應用的服務端:

  • 調用create_channel為每個客戶端創建一個channel,并將channel的url返回給客戶端。
  • 處理channel server發過來的客戶端上行消息(如果有的話)。
  • 有消息要發送時,調用send_message來向客戶端推送消息。

當JS客戶端和channel服務端連接上/斷開或者當JS客戶端有發送消息給channel服務器時,channel服務器會使用http回調的方式通知應用。

回調地址 事件說明
/_sae/channel/connected 客戶端連接上channel服務器
/_sae/channel/disconnected 客戶端和channel服務器斷開
/_sae/channel/message 客戶端有上行消息,POST內容的message字段為JS客戶端發送的內容

所有的http回調都使用POST方法。所有http回調的POST內容中的from字段為客戶端對應channel的名稱。其余字段(如果有)見具體回調說明。

注解

每個html頁面最多可以建立1個channel連接。

API使用手冊?

Server端API:

點擊查看

Javascript客戶端API:

在html頁面中使用以下代碼引用Channel服務的js庫。

<script type="text/javascript" src="http://channel.sinaapp.com/api.js"></script>
class sae.Channel(url)
參數:
  • url (string) – 服務端create_channel()返回的url地址
sae.Channel.onopen

設置客戶端連接上服務端時的回調函數。

sae.Channel.onmessage

設置客戶端收到消息時的回調函數。該函數接受一個參數:一個messagae對象,其中的data字段為服務端send_message接口發送的消息內容。

sae.Channel.onerror

設置客戶端和服務端連接出現錯誤時的回調函數。

sae.Channel.onclose

設置客戶端關閉和服務端的連接時的回調函數。

使用示例?

下面我們使用 TicTacToe(井字棋) 游戲來示范Channel服務的使用方法:

完整代碼:https://github.com/sinacloud/sae-channel-examples/tree/master/php

channel的創建和連接

首先,當用戶A打開TicTacToe游戲的主頁時,TicTacToe服務端的程序會:

  • 調用 createChannel 創建為用戶A創建一個channel,并將該channel的url嵌入到返回給用戶的html頁面代碼中。
  • 生成一個加入游戲的連接,用戶通過將此連接發送給其它用戶B,其它用戶B可以通過此連接加入用戶A創建的游戲。

每個頁面對應的channel的name應該是獨一無二的,比如可以使用用戶id的字符串作為channel的name。

游戲的主頁的html代碼模板大致如下所示,其中 <?=$url ?><?=$game_link?> 分別為上面生成的channel url和游戲加入連接。

<head>
...
<script src="http://channel.sinaapp.com/api.js"></script>
</head>
<body>
  <script>
    socket = new sae.Channel('<?=$url?>');
    socket.onopen = onOpened;
    socket.onmessage = onMessage;
    socket.onerror = onError;
    socket.onclose = onClose;
  </script>

  ...

  <div id='other-player' style='display:none'>
    Waiting for another player to join.<br>
    Send them this link to play:<br>
    <div id='game-link'><a href='<?=$game_link?>'><?=$game_link?></a></div>
  </div>

</body>

游戲的js客戶端使用 sae.Channel 來創建一條channel連接,并且設置channel的onopen/onmessage/onerror/onclose的callback函數。

使用channel來推送游戲狀態信息

當用戶B點擊用戶A發過來的連接打開了游戲頁面時,游戲的javascript客戶端通過 sendMessage 函數通知服務端。

onOpened = function() {
  connected = true;
  sendMessage('opened');
  updateBoard();
};

sendMessage = function(path, opt_param) {
  path += '?g=' + state.game_key;
  if (opt_param) {
    path += '&' + opt_param;
  }
  var xhr = new XMLHttpRequest();
  xhr.open('POST', path, true);
  xhr.send();
};

服務端更新當前游戲的狀態,并且通過channel的 sendMessage 將游戲的新的狀態發送給用戶A和用戶B的channel客戶端。客戶端接受到消息后更新游戲頁面。此后用戶A和用戶B交替走棋,客戶端通過 sendMessage 將用戶的走法發送給服務端。

moveInSquare = function(id) {
  if (isMyMove() && state.board[id] == ' ') {
    sendMessage('/move', 'i=' + id);
  }
}

服務收到消息后更新游戲的狀態,再通過 sendMessage 將更新后的狀態發送給用戶A和B,如此往復直到游戲結束為止。

<?php

switch ($action) {
  case 'opened':
    $game_key = $_REQUEST['g'];
    $game = Game::get_by_key_name($game_key);
    $game_updater_instance = new GameUpdater($game);
    $game_updater_instance->send_update();
    break;
  case 'move':
    $game_key = $_REQUEST['g'];
    $game = Game::get_by_key_name($game_key);
    $user = $_COOKIE['u'];
    if ($game and $user) {
      $id = $_REQUEST['i'];
      $game_updater_instance = new GameUpdater($game);
      $game_updater_instance->make_move($id,$user);
    }
    break;
  default:
    die('Illegal request');
}

class GameUpdater
{
    public $game;
    function __construct($game)
    {
      $this->game = $game;
      $this->channel = new SaeChannel();
    }

    function get_game_message()
    {
      $GameUpdater = array(
        'board' => $this->game->board,
        'userX' => $this->game->userX,
        'userO' => $this->game->userO,
        'moveX' => $this->game->moveX,
        'winner' => $this->game->winner,
        'winningBoard' => $this->game->winning_board,
        );
      return json_encode($GameUpdater);
    }

    function send_update()
    {
      $message = $this->get_game_message();
      $this->channel->sendMessage($this->game->userX.$this->game->key_name,$message);
      if ($this->game->userO) {
        $this->channel->sendMessage($this->game->userO.$this->game->key_name,$message);
      }
    }

    function check_win()
    {
      if ($this->game->moveX) {
          # O just moved, check for O wins
          $potential_winner = $this->game->userO;
          $wins = array_map(function($a){return str_replace('X','O',$a);},Wins::$x_win_patterns);
          //$wins = Wins::$o_win_patterns;
      } else {
          $potential_winner = $this->game->userX;
          $wins = Wins::$x_win_patterns;
      }
      foreach ($wins as $small) {
        if ( $this->check_regual( $this->game->board, $small) ) {
          $this->game->winner = $potential_winner;
          $this->game->winning_board = $small;
          return true;
        }
      }
      return false;
    }

    ...

    function make_move( $position, $user )
    {
      if ($user>0 and $user == $this->game->userX or $user == $this->game->userO) {
        if($this->game->moveX == ($user == $this->game->moveX)) {
          $boardList = $this->str2array($this->game->board);
          if ($boardList[$position] == ' ') {
            $boardList[$position] = $this->game->moveX ? 'X' : 'O';
            $this->game->board = implode("", $boardList);
            $this->game->moveX = !$this->game->moveX;
            $this->check_win();
            $this->game->put();
            $this->send_update();
            return true;
          }
        }
      }
      return false;
    }

    ...
}

GameUpdater類檢查move的請求是否合法,如果合法則更新游戲的狀態并且通知游戲雙方新的游戲狀態。

河南22选5开奖
  • <em id="xpjve"><ol id="xpjve"></ol></em>

          1. <em id="xpjve"><ol id="xpjve"></ol></em>