天天看點

websocket協定—socket.io設計一個簡易聊天室 (二)

介紹了原生websocket的使用,接着學習使用socket.io:

socket.io 是基于 WebSocket 的 C-S 實時通信庫,底層是 engine.io,這個庫實作了跨平台的雙向通信。

engine.io 使用了 WebSocket 和 XMLHttprequest(或JSONP) 封裝了一套自己的 Socket 協定(暫時叫 EIO Socket),在低版本浏覽器裡面使用長輪詢替代 WebSocket。一個完整的 EIO Socket 包括多個 XHR 和 WebSocket 連接配接.

常用api:

socket.emit

資料傳輸對象為目前socket對應的client,其他各個client socket互相不影響;

socket.broadcast.emit

資料傳輸對象為所有client,排除目前socket對應的client;

io.sockets.emit

資料傳輸對象為所有client,包括觸發目前事件的client;

使用:

1.安裝express,聊天室需要區域網路的呀,區域網路需要啟動http服務呀,是以安裝express;

2.安裝socket.io,cnpm i --save socket.io   裝好後它分為前端、後端兩部分,前端頁面引入:<script src="/socket.io/socket.io.js"></script>(在檔案中看不到,等連接配接服務的時候就會出現),會自動生成一個檔案夾名字就叫socket.io,以及檔案夾内生成socket.io.js檔案

3.建立mainjs檔案,開始撸:

直接貼出寫好的代碼了:

mainjs:

var express = require("express");
var app = express();
//因為socket.io依賴原生http服務,是以要引入原生http子產品,并且調用它的Server()方法将app傳入,這樣原生的http就擁有了express的方法
var http = require("http").Server(app);
var socket = require("socket.io")(http);//傳入http執行socket函數,這樣socket就跟http具有同一個端口了
http.listen(9999);

app.use(express.static("./html"));//設定靜态資源路徑

// 建立socket監聽服務:
socket.on("connection", function(ws){
	ws.on("diyLogin", function(val){//定義一個完全自定義事件,用來擷取前端發來的登入的使用者名
		var address = ws.handshake.address;
		console.log(address);
		var u =  checkUser(val);
		if(u.err){
            ws.emit("exist", u);
        }else{
        	socket.sockets.emit("allLogin", u);//執行前端事件,發送範圍為每一個線上的用戶端
        }
	});

	ws.on("sendMsg", function(msgObj){
		socket.sockets.emit("accept", msgObj);//把接收到的某個使用者消息發送到所有用戶端
	})
	
})

var arr = [];
function checkUser(u){//檢測使用者名是否已存在
	if(arr.length === 0){
		arr.push(u);
		return u;
	};
	for(var i = 0; i < arr.length; i++){
		if(arr[i] === u){
			return {
				err: "使用者名已存在",
				users: arr
			}
		}
	}
	arr.push(u);
	return u;
}
           

html:

<!DOCTYPE html>
<html >
<head>
	<meta charset="UTF-8">
	<title>Document</title>
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" target="_blank" rel="external nofollow"  integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
	<style>
    i{
        font-style: normal;
    }
       .chatList{
       	  height: 200px;
       	  border: 1px dashed green;
       	  overflow-y: auto;
       }
       .myself{
       	  text-align: right;
       	  color: red;
       }
       i.lin{
        font-weight: bold;
        color: #ffcc01;
        font-size: 16px;
       }
       i.other{
        color: green;
       }
       p.me{
        text-align: right;
        color: orange;
       }
	</style>
</head>
<body>
	<div class="container">
		<div class="loginBox">
			  <input type="text" class="form-control" id="username">
		      <button class="btn" id="sure">登入</button>
		</div>
        <div class="chatBox hidden">
        	<div class="chatList">
        		
        	</div>
            <textarea class="form-control" id="msg" cols="30" rows="5"></textarea>
            <button class="btn" id="send">發送</button>
            <div class="alert alert-success hidden" role="alert"></div>
        </div>
	</div>
</body>
<script src="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src="/socket.io/socket.io.js"></script>
<script>
	//連結socket
    var ws = io.connect("ws://localhost:9999");
    var user;
    $("#sure").click(function(){
        var name = $("#username").val();
        if(!name){
            alert("好歹起個名呀,eg:李易峰");
        }else{
            //通知背景有人登陸了,socket.io都是基于事件的,要做的操作都是觸發自定義事件的方式
            ws.emit("diyLogin", name);//執行自定義事件傳入使用者名
            user = name;//把目前使用者名稱儲存到全局變量
        }
   })
    //擷取後端傳回的使用者是否存在的查詢結果
    ws.on("exist", function(re){
        if(re.err){
            alert(re.err);
            console.log("已經登陸的使用者:\n", re.users)
            return;
        }
    })

    //接收後端傳回的全局的登入者的名字的事件
    ws.on("allLogin", function(name){
        var _alert = name === "趙治林" ? "歡迎 男爵 <i class='lin'>"+name+"</i> 騎着火麒麟來到了本直播間!" : "<i class='other'>"+name+" </i>進入直播間";
         $(".alert").html(_alert).removeClass("hidden").show();
         $(".loginBox").hide();//登陸後隐藏登入盒子
         $(".chatBox").removeClass("hidden");//顯示出聊天界面
         setTimeout(function(){
            $(".alert").fadeOut(function(){
                $(this).addClass("hidden");
            });
         }, 1500)
    })
    //發送聊天消息
    $("#send").click(function(){
        var msg = $("#msg").val();
        if(!msg){
            alert("空消息也要錢哦!");
        }else{
            ws.emit("sendMsg", {msg, user});//執行事件把内容和發送者發送給背景,讓背景傳回給所有用戶端
            $("#msg").val("");
        }
    })
    //接收聊天消息
    ws.on("accept", function(o){
        var p = $(`<p>${o.user}: ${o.msg}</p>`)
        if(o.user === user){
            p.addClass("me");
        }
        $(".chatList").append(p).scrollTop($(".chatList")[0].scrollHeight);
    })
</script>
</html>
           

個人了解:

socket.io實作了一對多的B-S雙向通信,是基于事件驅動的,相當于背景自定義一個事件,前端觸發,前端自定義一個事件,背景觸發,同時可以選擇socket.io提供的方法指定資料發送的範圍,比如發給哪一個用戶端;