微信扫一扫

028-83195727 , 15928970361
business@forhy.com

WebSocket入门教程(五)-- WebSocket实例:简单多人聊天室

2016-06-09

转载请标明出处:http://blog.csdn.net/u010136741/article/details/51612594, 本文出自: 柳木木_kylin

【总目录】


WebSocket入门教程--大纲

【实例简介】


    本文,我们通过nodejs和javascript实现一个网页聊天室的demo。主要包括,聊天,改用户名,查看其他用户在线状态的功能。大致流程为,用户访问网页,即进入聊天状态,成为新游客,通过底部的输入框,可以输入自己想说的话,点击发布,信息呈现给所有在聊天的人的页面。用户可以实时修改自己的昵称,用户离线上线都会实时广播给其他用户!


【效果图】





【客户端】


    web页面主要呈现在线人数,聊天信息,一个输入框和发送按钮,上代码:

<!DOCTYPE html>
<html lang="cn">
<head>
	<title>WebSocket chart application</title>
	<meta charset="utf-8">
	<meta name="viewport" content="width=device-width, initial-scale=1">
	<link rel="stylesheet" href="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/css/bootstrap.css">
	<link rel="stylesheet" href="http://cdn.bootcss.com/tether/1.3.2/css/tether.css"/>
	<script src="http://cdn.bootcss.com/jquery/2.2.4/jquery.js" ></script>
	<script src="http://cdn.bootcss.com/tether/1.3.2/js/tether.js"></script>
	<script src="http://cdn.bootcss.com/bootstrap/4.0.0-alpha.2/js/bootstrap.js"></script>
	<script>
		var ws= new WebSocket('ws://www.liumumu.top:8180');
		var nickname;
		ws.onopen = function(e){
			console.log('Connection to server opened');
		}
  		function appendLog(type,nickname, message,clientcount) {
          		var messages = document.getElementById('messages');
          		var messageElem = document.createElement("li");
          		var preface_label;
			if(type==='notification') {
                  		preface_label = "<span class=\"label label-info\">*</span>";
              		} else if(type==='nick_update') {
                  		preface_label = "<span class=\"label label-warning\">*</span>";
              		} else {
                  		preface_label = "<span class=\"label label-success\">" + nickname + "</span>";
              		}
          		var message_text = "<h2>" + preface_label + "  " + message + "</h2>";
          		messageElem.innerHTML = message_text;
          		messages.appendChild(messageElem);
			var count_people = document.getElementById("count_people");
                        count_people.innerHTML = clientcount;

        	}
		ws.onmessage = function(e){
			var data = JSON.parse(e.data);
			nickname = data.nickname;
          		appendLog(data.type,data.nickname, data.message,data.clientcount);
        		console.log("ID: [%s] = %s", data.id, data.message);


		}
		function sendMessage(){
			var message = $('#message').val().trim();
			if(message.length<1){
				alert("不能发送空内容!");
				return;
			}
			ws.send($('#message').val());
			$('#message').val("");
			$('#message').focus();
			console.log(ws.bufferedAmount);
		}
	</script>
</head>
<body lang="cn">
    <div class="vertical-center">
    <div class="container">
        <h2>多人在线聊天DEMO</h2>
	<hr />
	<p>当前在线人数:<span id="count_people">0</span></p>
 	<ul id="messages" class="list-unstyled">

    	</ul>
    	<hr />
   	<form role="form" id="chat_form" onsubmit="sendMessage(); return false;">
        	<div class="form-group">
        		<input class="form-control" type="text" name="message" id="message"
          			placeholder="输入聊天内容" value="" autofocus/>
        	</div>
       		<button type="button" id="send" class="btn btn-primary"
          onclick="sendMessage();">发送!</button>
    </form>
    </div>
    </div>
</body>
</html>
    
    javascript 部分,连接websocket成功之后,主要是监听数据返回,和发送数据。
    当用户编辑好内容,点击发送按钮是调用sendMessage方法,发送数据,如果需要修改昵称,则发送数据格式为"/nick 昵称"。
   当服务器返回数据到客户端,我们通过appendLog方法对数据做处理,根据type字段,判断是显示用户离线在线信息,还是显示聊天信息。最后更新在线人数。

【服务器端】


    服务器端主要是接收信息,判断是聊天信息还是重命名信息,然后发送广播。同时,当用户连接上服务器端或者关闭连接时,服务器也会发送广播通知其他用户。
var WebSocket = require('ws');
var WebSocketServer = WebSocket.Server,
    wss = new WebSocketServer({port: 8180});
var uuid = require('node-uuid');

var clients = [];

function wsSend(type, client_uuid, nickname, message,clientcount) {
  for(var i=0; i<clients.length; i++) {
    var clientSocket = clients[i].ws;
    if(clientSocket.readyState === WebSocket.OPEN) {
      clientSocket.send(JSON.stringify({
        "type": type,
        "id": client_uuid,
        "nickname": nickname,
        "message": message,
        "clientcount":clientcount,
      }));
    }
  }
}

var clientIndex = 1;

wss.on('connection', function(ws) {
  var client_uuid = uuid.v4();
  var nickname = "游客"+clientIndex;
  clientIndex+=1;
  clients.push({"id": client_uuid, "ws": ws, "nickname": nickname});
  console.log('client [%s] connected', client_uuid);

  var connect_message = nickname + " 来了";
  wsSend("notification", client_uuid, nickname, connect_message,clients.length);

  ws.on('message', function(message) {
    if(message.indexOf('/nick') === 0) {
      var nickname_array = message.split(' ');
      if(nickname_array.length >= 2) {
        var old_nickname = nickname;
        nickname = nickname_array[1];
        var nickname_message = "用户 " + old_nickname + " 改名为: " + nickname;
        wsSend("nick_update", client_uuid, nickname, nickname_message,clients.length);
      }
    } else {
      wsSend("message", client_uuid, nickname, message,clients.length);
    }
  });

  var closeSocket = function(customMessage) {
    for(var i=0; i<clients.length; i++) {
        if(clients[i].id == client_uuid) {
            var disconnect_message;
            if(customMessage) {
                disconnect_message = customMessage;
            } else {
                disconnect_message = nickname + " 走了";
            }

          clients.splice(i, 1);
          wsSend("notification", client_uuid, nickname, disconnect_message,clients.length);
        }
    }
  }
  ws.on('close', function() {
      closeSocket();
  });

  process.on('SIGINT', function() {
      console.log("Closing things");
      closeSocket('Server has disconnected');
      process.exit();
  });
});

    我们定义了wsSend函数用来处理消息的广播。对每个连接的用户,我们默认给他分配为游客。为了实现广播,我们用clients数组来保存连接的用户。

【演示地址】


电脑访问:

手机浏览器、微信访问:



【源码下载】


【结束语】


    对比前面的demo,本文的demo增加了客户端与服务器的互动,同时也实现了客户端之间的联系。不管是功能还是代码,都有很多可以完善的地方,广大读者可以在此基础上,添加更多的功能。