前言:

因為最近公司有個特別的活動,想要做到類似下面這個網頁的功能

這個是孔劉打電話給我的活動,下面這邊有活動玩法的介紹

http://www.adaymag.com/2017/04/11/bcdate-korea-gong-yoo.html

要怎麼玩咧?

1. 首先打開你電腦上的瀏覽器,輸入網址:http://www.nowbc.net/

2. 然後再打開你手機的瀏覽器,輸入網址:http://www.bcdate.kr/

3. 然後在手機上輸入你在電腦上看到的四位數認證碼,讓電腦跟手機進行配對

然後電腦版瀏覽器就會播放孔劉打給你的影片,然後手機就真的來電了

但當然不是真的來電,只是做的跟真的來電有 87%分像

然後行銷說要做這個........我第一時間以為我終於可以去寫 node.js 了

但後來主管說,他曾在多年前某個研討會講過 Signal R 的介紹與使用方式

可以很簡單的實作出這個功能,重點是還有 jQuery 的套件可以直接用

因為很有趣聽起來也很簡單,所以就開始研究了一下

也是真的很簡單,大概不用一天就可以摸熟了

以下就開始介紹

 

SignalR 的介紹

網路上實在是太多高手了,所以請直接看高手來介紹發展史跟架構,我這篇只是在介紹我自己的學習心得

下面這篇講解得很清楚

https://blogs.msdn.microsoft.com/msdntaiwan/2013/09/09/signalr-web-web/

簡單來說,SignalR 把 Comet 概念與 WebSocket 整個包在一起了,而且效能與傳輸效率都比較好

有關 Comet 介紹看這裡:https://zh.wikipedia.org/wiki/Comet_(web%E6%8A%80%E6%9C%AF)

有關 WebSocket 介紹看這裡:https://zh.wikipedia.org/wiki/WebSocket

架構簡化後,大概如下面我手殘用小畫家畫的圖:

電腦版網頁與行動版網頁,中間透過一個 SignalR Hub 來做訊息的傳遞與接收

SignalR Hub 是中間溝通的橋樑,我們利用 C# 來開發,電腦版與行動版網頁就利用  jQuery 來呼叫

在開始前先簡述一下流程

1. Client A 電腦版網頁執行時,先對 SignalR Hub 建立連線,連線時產生四位數的號碼,讓其他裝置配對

2. Client B行動版網頁執行時,建立對 SignalR Hub 的連線,然後從手機上輸入四位數字後按下送出

    然後將四位數字傳遞到 SignalR Hub 檢查與比對,如果號碼與 Client A 一致就配對成功

3. 配對完成之後,之後就可以在 Hub 使用 ConnectionID 屬性來指定要讓哪個裝置動作了

我們可以把 Hub 當成是一個資料儲存與處理的地方,儲存著所有連線的紀錄與要執行的事件處理

要注意的是,要共用的變數都必須要設定成靜態才行

 

簡單的開發步驟

以下就實際的來開始開發,有問題隨時可以看官網

https://docs.microsoft.com/en-us/aspnet/signalr/

 

第一步:建立環境

首先我們先建立一個空白的新網站

然後從 NuGet 搜尋 SignalR,安裝底下這兩個

Microsoft.AspNet.SignalR

Microsoft.AspNet.SignalR.Client

然後你會發現 Scripts 裡面已經下載好 jQuery 1.6.4 版本,還有 signalR 的 jQuery 套件

 

第二步:建立 SignalR Hub 與 OWIN 啟動類別

1. 我們新增一個新項目,類型選擇 SignalR Hub 類別 (v2)

然後名字先取名叫 PageHub.cs,我們要先來做 SignalR Hub

 

2. 在開始寫 Hub之前,我們要先建立 OWIN 啟動類別 OWIN 全名是 Open Web Interface for .NET

官網:http://owin.org/

可以看一下黑暗執行續大大的解釋:http://blog.darkthread.net/post-2013-12-01-about-owin.aspx

這東東的功用,擷取文內的說明

意思是ASP.NET程式可以不依賴System.Web.dll,不侷限於IIS,放在Console程式裡跑Self-Hosting模式,甚至透過Kayak網站伺服器在*nix系統運作

所以我們先來新增一個 OWIN 啟動類別,然後取名叫做 Startup.cs

然後將你的 Startup.cs 加上下面紅字那行

using System;
using System.Threading.Tasks;
using Microsoft.Owin;
using Owin;
[assembly: OwinStartup(typeof(signalr2.Startup))]
namespace signalr2
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
//加上底下這行
app.MapSignalR();
}
}
}

然後就完成了環境的設定

 

第三步:開始來寫 Hub 的功能

 再來繼續打開上個步驟新增的 PageHub.cs 要來寫 SignalR Hub 的功能

 因為我們要在 Hub 上記錄連線配對的狀況,所以我們需要有個地方來儲存這些資料

你可以用 SQL、SQLite、又或者是用變數來記錄,只是如果使用者爆量,記憶體也可能吃很兇

因為是練習,所以我用 List 來記錄,因此我建了一個 Player 物件來存放連線配對的資料

要注意的是,Hub 裡面共用的變數都要是 private static 的靜態變數

新增一個類別,名字叫做 Player.cs 用來記錄連線資料

每個連線會有獨特的 ConnectionID,因此這個物件會把 ConnectionID 與輸入的四位號碼記錄下來

然後回顧一下我們的需求

我們一開始在電腦版網頁載入時,要動態產生四個數字讓行動版配對

因為這四個數字必須要是獨一無二不能重複,不然如果重複了你要怎麼知道跟誰配對?

所以必須透過 Hub 來記錄,最好的方法就是直接在 Hub 產生四個數字

所以我們在 Hub 寫了以下這段 code

/// <summary>
/// 產生四碼不重複數字
/// </summary>
/// <returns></returns>
public string CreateCode()
{
Random rnd = new Random();
string code = rnd.Next().ToString().Substring(0, 4);
do
{
code = rnd.Next().ToString().Substring(0, 4);
} while (playerList.Where(p => p.Code == code).Count() > 0);
//先移除上次產生的號碼,如果有的話
playerList.RemoveAll(p => p.ConnectionID == Context.ConnectionId);
//要求產生號碼時,紀錄連線的 ConnectionId,還有上面產生的四個不重複數字
playerList.Add(new Player { ConnectionID = Context.ConnectionId, Code = code });
return Clients.Client(Context.ConnectionId).getCode(code);
}

 

上面這段 code 主要是在產生四個不重複數字

然後把要求建立連線裝置的 Context.ConnectionId 給記錄在 Play 物件裡面

紅色字的那段比較重要,是用來把資訊傳遞到 client 的 getCode 事件中

如果你要指定是哪個 Client 裝置,就要用 Clients.Client(連線的編號) 去指定

如果是全部的 Client 都要,那可以用 Clients.All

不管是 Clients.Client(連線的編號),還是 Clients.All,後面接的都是在 client 端 js 的方法名稱

以下面這段為例:

Clients.Client(Context.ConnectionId).getCode(code);

getCode 指的就是傳遞到 Client js 的 getCode方法

如果你第一個字是大寫的 GetCode,到了 client js 第一個字要記得小寫 

 

第四步:開始來寫 Client 端的傳送與接收

接下來我們到 Client A 電腦版的網頁,來接收一下這四個號碼

首先電腦版網頁中請引用一下 js library

<script type="text/javascript" src="Scripts/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.signalR-2.2.2.min.js"></script>
<script type="text/javascript" src="signalr/hubs"></script>

你會發現第三行是來亂的,根本沒看到這個目錄,但你還是要引用

signarr/hubs 是一個 signalR 自動生成的目錄,有關橋接的 js 都會生成在這邊

然後準備一下 HTML + 美美的 CSS 來迎接四個數字

畫面長的像下面這樣

再來就是電腦版 js 的部分,第一步要溝通,就要先建立跟 Hub 的連線

以下先寫 code 再解釋

 

<script type="text/javascript" src="Scripts/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.signalR-2.2.2.min.js"></script>
<script type="text/javascript" src="signalr/hubs"></script>
<script>
var player = $.connection.pageHub;
player.client.getCode = function (message) {
for (let i = 0; i < 4; i++) {
$("#input div:eq(" + i + ")").html(message.substr(i, 1));
}
};
$.connection.hub.start().done(function () {
player.server.createCode();
});
</script>

 

由於我們的 Hub 名稱叫 PageHub (class name)

所以透過 $.connection.pageHub 名稱去建立連線,然後把連線物件放到 player 變數中

然後在 js 最下方,當 hub 完成連線的時候,我們呼叫 hub 上的 createCode() 方法

Hub 的 CreateCode() 就會吐四個數字給 client 的 getCode

所以有了下面這行,把 Hub 傳遞過來的數字填到 html 裡面

player.client.getCode = function (message) {
for (let i = 0; i < 4; i++) {
$("#input div:eq(" + i + ")").html(message.substr(i, 1));
}
};

要記得在 hub 傳遞參數到 client 要用 Clients.Client(連線的編號)

在 client 要傳遞資料到 server 時,要用連線物件.server 去呼叫方法

於是數字就填進來了

當然這四個數字,跟這個裝置的 ConnectionId 已經被我們記在 Hub 的 List 變數裡了

接下來就是要在手機輸入這四個數字,完成配對動作

 

第五步:行動裝置網頁與電腦版網頁配對

首先我們弄一個簡單的 html 讓使用者輸入四個數字,才能進行配對

然後先放一張隱藏的圖,連線中的時候放一個等待圖

長得像這樣

然後是 js 的部分,一樣先建立連線

<script type="text/javascript" src="Scripts/jquery-1.6.4.min.js"></script>
<script type="text/javascript" src="Scripts/jquery.signalR-2.2.1.min.js"></script>
<script type="text/javascript" src="signalr/hubs"></script>
<script>
var player = $.connection.pageHub;
$("#match").click(function () {
player.server.findSameCode($("#code").val());
});
$.connection.hub.start().done();
</script>

然後輸入完後按下配對,會把輸入的四個數字傳到 Hub 去檢查是否有相同的代碼

因此我們必須要在 Hub 上寫一個 FindSameCode 的方法去檢查,並配對

/// <summary>
/// 配對
/// </summary>
/// <param name="code"></param>
public void FindSameCode(string code) {
player = playerList.FirstOrDefault(p => p.Code == code && p.Code2 == null);
if (player == null)
{
Clients.Client(Context.ConnectionId).matchMsg(false);
}
else
{
player.ConnectionID2 = Context.ConnectionId;
player.Code2 = code;
Clients.Client(Context.ConnectionId).matchMsg(true);
Clients.Client(player.ConnectionID).matchMsg(true);
}
}

Hub 的 FindSameCode 方法就會去檢查之前紀錄的連線編號

如果輸入的數字與記錄中的編號相符,且還沒有進行連線的話,就會呼叫兩端的 matchMsg 確認連線

如果號碼相符但已經連線過了,就會對要求連線的裝置回傳 false

所以我們要在電腦版與行動版 client 加上一個 matchMsg 的方法,去檢查連線是否成功

然後把等待的轉轉圖顯示五秒後隱藏

player.client.matchMsg = function (message) {
if (message) {
console.log("已配對");
$("#match").hide();
$("#loading").removeClass("hidden").delay(5000).queue(function () {
$(this).addClass("hidden")
});
} else {
console.log("配對失敗");
}
};

 

以上就完成了配對,之後的動作就都很簡單了

你可以在 Hub 同時發送訊息給連線中的 Client,或是經由 Client A 發送訊息經由 Hub 給 Client B

然後最後要記得斷線時要把連線清掉才行,只要離開頁面都會被認定為斷線

所以覆寫一下 OnDisconnected,把所有的有關關連線編號的連線移除

public override Task OnDisconnected(bool stopCalled)
{
return DeleteCode();
}
/// <summary>
/// 斷線時清除使用者
/// </summary>
public Task DeleteCode()
{
playerList.RemoveAll(p => p.ConnectionID == Context.ConnectionId);
return null;
}

最後文章懶得寫了,可以看一下這一個簡易的 demo 就可以知道效果

 

DEMOhttps://www.suncolor.com.tw/41/

網頁上有QR Code,用手機掃一下然後輸入 4個數字就可以玩了

SignalR 在網頁上可以應用的地方除了小遊戲,其他如線上客服、聊天室....應該也可以很簡單的做到

參考資料:

https://docs.microsoft.com/en-us/aspnet/signalr/overview/getting-started/introduction-to-signalr

 

arrow
arrow
    全站熱搜

    小雕 發表在 痞客邦 留言(5) 人氣()