iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 16
1

安裝websocket

npm install --save websocket

server.js

const http = require('http');
const ws = require('websocket').server;

// 建立server 並監聽Port 9999
const PORT = 9999;
const server = http.createServer().listen(PORT)

// 產生websocketServer
webSocketServer = new ws({
  httpServer: server
});

//當使用者連入時 觸發此事件
webSocketServer.on('request', request => {
  const connection = request.accept('echo-protocol', request.origin);

  //當websocket server收到訊息時 觸發此事件
  connection.on('message',  event => {
    let data = JSON.parse(event.utf8Data)
    console.log(`接收訊息${ JSON.stringify(data) }`)
    switch (data.type) {
      case 'connect':
        console.log(`user: ${ data.userName },\n 
                     connect on: ${ new Date(data.date) }`)
        break;
    
      default:
        break;
    }
    // connection.send("收到訊息: " + message.utf8Data);
  });

  //當使用者socket連線中斷時 例如:關閉瀏覽器 觸發此事件
  connection.on('close', (reasonCode, description) => {
    console.log('connection close.');
  });
});

接著啟動伺服器

node server.js

注意 'echo-protocol' 此字串為和client端約定的協議, client端可以一次發送許多不同協議進行連線, 一個server端也可以一次處理多個不同的協議, 以應付不同的互動狀態

client端使用websocket進行連線

//建立WebSocket 連到127.0.0.1 Port為9999
//echo-protocol為約定好的自訂protocol 在WebSocket Server端也要設定
const mySocket = new WebSocket("ws://127.0.0.1:9999", "echo-protocol");

//Socket接收訊息時會呼叫此函數,處理接收到的訊息
mySocket.onmessage = e => {
  console.log(e.data)
}

mySocket.onopen = e => {
  let data = {
    type: 'connect',
    userName: this.userName, 
    date: Date.now()
  }
  mySocket.send(JSON.stringify(data))
}

mySocket.onclose = e => {
  console.log('與伺服器失去連線')
}

建立WebSocket物件時, 第二個參數 "echo-protocol", 可以傳入一個陣列, 處理不同的互動情形

ws和伺服器溝通取得題目

在接收websocket訊息的callback中取得狀態'is_match'後, 可以確保雙方玩家都已經加入遊戲,
此時已經可以向server發出訊息'getQuestion'取得題目

case 'isMatch':
  console.log('已經加入遊戲!')
  setTimeout(() => { 
    mySocket.send(JSON.stringify({
      type : 'getQuestion',
      id : data.id,
      userName: VM.userName
    }))
  }, 5000);
  break;

server中的實作, getQuestion function處理前端丟過來的 'getQuestion' 狀態,
GAME物件中有一個getQuestion的方法, 是我們真正取得當前題目的地方,
這邊最重要的地方是處理isPlayerOneReady和questionStep(第幾條題目)的狀態,
否則會產生兩位玩家題目不同步的問題,最後在沒有題目之後,送回'gameOver'的狀態

getQuestion (data) {
  try {
    console.log(`room: ${ data.id } asking question.`)

    const GAME = gameRoomsList.filter((value) => {
      return value.id === data.id
    })[0].room;
    
    let question = GAME.getQuestion();

      if ( GAME.isPlayerOneReady ) {
        GAME.isPlayerOneReady = false
        GAME.questionStep += 1
      }else {
        GAME.isPlayerOneReady = true
      }

      let res = {
        id : data.id
      };
      if ( question ) {
        res.type = 'question'
        res.question = question.question
        res.optionA = question.optionA
        res.optionB = question.optionB
      }else {
        res.type = 'gameOver'
      }

      connection.send(JSON.stringify(res))

  } catch (error) {
    connection.close()
    throw error
  }

上一篇
webSocket intro. (3/4
下一篇
17 day
系列文
GAME30天30

尚未有邦友留言

立即登入留言