12/08/2018, 16:24

Tìm hiểu cơ bản cách hoạt động của Socket Io bằng chat realtime

Cài đặt ban đầu Để bắt đầu ta cần cài đặt node Js trước, để cài đặt các bạn có thể vào trực tiếp trang https://nodejs.org/en/download/ để down về theo từng hệ điều hành. Giờ ta tạo 1 folder riêng cho project: mkdir chat_with_nodejs Sau khi tao xong ta vào folder đó rồi ta tạo file package.json. ...

Cài đặt ban đầu

Để bắt đầu ta cần cài đặt node Js trước, để cài đặt các bạn có thể vào trực tiếp trang https://nodejs.org/en/download/ để down về theo từng hệ điều hành. Giờ ta tạo 1 folder riêng cho project: mkdir chat_with_nodejs Sau khi tao xong ta vào folder đó rồi ta tạo file package.json. Tại đây ta chỉ cần 2 thư viện là express js với iosocket theo version mới nhât. { "name": "chat_with_node_js", "description": "Chat with nodejs - Viblo - Framgia VN", "version": "0.0.1", "dependencies": { "express": "", "socket.io": "" } } Sau khi tạo xong ta chạy lệnh npm install -d Sau khi chạy xong folder sẽ thêm 1 folder mới là node_modules, đó là tất cả thư viện mà ta đã khai báo trong file package.json . ### Chat trong 1 room ### Giờ tiếp theo ta làm chat realtime với nhiều user khác nhau trong 1 room. Trước khi làm ta cần thông nhất về trình tự như sau:

  • Khi mới vào link sẽ hiển thị popup để nguời dùng gõ user name vào.
    
  • Sau khi gõ xong user thì tên user hiển thị trên dánh sách và có thông báo có user vào phòng.
    
  • Khi đó user có thể gõ nội dung chat.
    
  • Khi người dùng thoát trình duyệt thì sẽ có thông báo nguời dùng này đã thoát khỏi room.
    

Tạo giao diện

Giờ ta tạo 1 giao diện đơn giản cho nội dung chat, sẽ là 1 cột bên trái hiển thị danh sách thành viên trong room, và phần bên phải là phần chính hiển thị nội dung chat. Ta tạo 1 file index.html như sau:

<div style="float:left;awidth:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
	<b>Thành viên</b>
	<div id="users"></div>
</div>
<div style="float:left;awidth:300px;height:250px;overflow:scroll-y;padding:10px;">
	<div id="conversation"></div>
	<input id="data" style="awidth:200px;" />
	<input type="button" id="datasend" value="send" />
</div>

Khi đó giao diện như sau:

Khởi động phía server

Tất cả việc làm với nodejs ta tạo 1 file js là chat.js và đầu tiên ta khai báo các thư viện như express với iosocket như sau:

var express = require('express')
  , http = require('http');
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);

server.listen(8080);

Như vậy ta khai báo sẽ sử dụng port 8080 cho sự kiện chat này, vậy để chạy phần nodejs này ta cần chạy node chat.js sau đó mở trình duyệt ra gõ đường dẫn http://localhost:8080 là sẽ chạy được.

Bắt các sự kiện trên client và xử lý trên server

Như trình tự đã nói ở trên ta cần bắt các sự kiện.

Khi vào trình duyệt hiện popup bắt nhập user name
// on connection to server, ask for user's name with an anonymous callback
	socket.on('connect', function(){
		// call the server-side function 'adduser' and send one parameter (value of prompt)
		socket.emit('them_thanh_vien', prompt("Tên bạn là gì?"));
	});

Như đoạn này ta có thể thấy khi bắt đầu connect ta sẽ gọi đến sự kiện them_thanh_vien từ phía server. Vậy ta cần thêm sự kiện them_thanh_vien ở server như sau:

var usernames = {};
socket.on('them_thanh_vien', function(username){
		//Lưu tên thành viên
		socket.username = username;
		// Thêm thành viên này vào danh sách thành viên
		usernames[username] = username;
		// Hiển thị thông báo cho chính nguời dùng trình duyệt
		socket.emit('thong_bao', 'SERVER', 'Bạn đã vào room');
		// Hiển thị thông báo cho các thanh viên khác
		socket.broadcast.emit('thong_bao', 'SERVER', username + ' đã vào room');
		// Cập nhật lại danh sách thành viên
		io.sockets.emit('cap_nhat_thanh_vien', usernames);
	});

Như vậy ta có thể thấy phía server thì đầu tiên sẽ khai báo 1 biến chung là usernames lưu lại danh sách các user name. sau đó mỗi khi gọi sự kiện them_thanh_vien sẽ thêm vào biến này. Sau đó gọi sự kiện thong_bao cho phía client để hiện thông báo cho đối tượng đang ở trình duyệt và những người khác 2 loại thông báo khác nhau. Cuối cùng gọi sự kiện cap_nhat_thanh_vien từ phía client. Vậy giờ phía client ta cần thêm 2 sự kiện thong_baocap_nhat_thanh_vien như sau

socket.on('thong_bao', function (username, data) {
		$('#conversation').append('<b>'+username + ':</b> ' + data + '<br>');
	});
    socket.on('cap_nhat_thanh_vien', function(data) {
		$('#users').empty();
		$.each(data, function(key, value) {
			$('#users').append('<div>' + key + '</div>');
		});
	});
Sự kiện khi gõ nội dung chat

Bây giờ ta bắt sự kiện khi người dùng gõ nội dung sau đó bấm button send để gửi nội dung chat. Từ phía client ta bắt sự kiện đó như sau (ở đây ta sử dụng jquery để bắt sự kiện click )

$(function(){
		// when the client clicks SEND
		$('#datasend').click( function() {
			var message = $('#data').val();
			$('#data').val(');
			// tell server to execute 'sendchat' and send along one parameter
			socket.emit('gui_chat', message);
		});
});

Tại đây có thể hiểu là khi click vào button thì sẽ có biến message lấy nội dung ở textbox sau đó xóa trắng textbox rồi gửi cái message này lên server thông qua sự kiện gui_chat. Tuy nhiên ta cần bắt thêm sự kiện khi người dùng gõ enter cũng sẽ gửi nội dung chat

$('#data').keypress(function(e) {
			if(e.which == 13) {
				$(this).blur();
				$('#datasend').focus().click();
			}
		});

Vậy về phía server sẽ xử lý như sau

socket.on('gui_chat', function (data) {
		// we tell the client to execute 'updatechat' with 2 parameters
		io.sockets.emit('thong_bao', socket.username, data);
	});
Khi người dùng thoat trình duyệt

Sự kiện cuối cùng là khi người dùng thoát khỏi trình duyệt, việc này ta chỉ làm trên server

socket.on('disconnect', function(){
		// Xóa user khỏi biến chung
		delete usernames[socket.username];
		// cập nhật lại danh sách thành viên
		io.sockets.emit('cap_nhat_thanh_vien', usernames);
		// Hiển thị thông báo cho những nguời khác
		socket.broadcast.emit('thong_bao', 'SERVER', socket.username + ' has disconnected');
	});
    ```
 ### Nội dung các file ###
 ```chat.js
 var express = require('express')
  , http = require('http');
//make sure you keep this order
var app = express();
var server = http.createServer(app);
var io = require('socket.io').listen(server);

server.listen(8080);

// routing
app.get('/', function (req, res) {
  res.sendfile(__dirname + '/index.html');
});

// usernames which are currently connected to the chat
var usernames = {};

io.sockets.on('connection', function (socket) {

	// when the client emits 'sendchat', this listens and executes
	socket.on('gui_chat', function (data) {
		// we tell the client to execute 'updatechat' with 2 parameters
		io.sockets.emit('thong_bao', socket.username, data);
	});

	// when the client emits 'them_thanh_vien', this listens and executes
	socket.on('them_thanh_vien', function(username){
		// we store the username in the socket session for this client
		socket.username = username;
		// add the client's username to the global list
		usernames[username] = username;
		// echo to client they've connected
		socket.emit('thong_bao', 'SERVER', 'you have connected');
		// echo globally (all clients) that a person has connected
		socket.broadcast.emit('thong_bao', 'SERVER', username + ' has connected');
		// update the list of users in chat, client-side
		io.sockets.emit('cap_nhat_thanh_vien', usernames);
	});

	// when the user disconnects.. perform this
	socket.on('disconnect', function(){
		// remove the username from global usernames list
		delete usernames[socket.username];
		// update list of users in chat, client-side
		io.sockets.emit('cap_nhat_thanh_vien', usernames);
		// echo globally that this client has left
		socket.broadcast.emit('thong_bao', 'SERVER', socket.username + ' has disconnected');
	});
});
<script src="socket.io/socket.io.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script>
<script>
	var socket = io.connect('http://localhost:8080');

	socket.on('connect', function(){
		socket.emit('them_thanh_vien', prompt("Tên của bạn"));
	});

	socket.on('thong_bao', function (username, data) {
		$('#conversation').append('<b>'+username + ':</b> ' + data + '<br>');
	});

	socket.on('updateusers', function(data) {
		$('#users').empty();
		$.each(data, function(key, value) {
			$('#users').append('<div>' + key + '</div>');
		});
	});

	$(function(){
		$('#datasend').click( function() {
			var message = $('#data').val();
			$('#data').val(');
			// tell server to execute 'gui_chat' and send along one parameter
			socket.emit('gui_chat', message);
		});

		$('#data').keypress(function(e) {
			if(e.which == 13) {
				$(this).blur();
				$('#datasend').focus().click();
			}
		});
	});

</script>
<div style="float:left;awidth:100px;border-right:1px solid black;height:300px;padding:10px;overflow:scroll-y;">
	<b>Thành viên</b>
	<div id="users"></div>
</div>
<div style="float:left;awidth:300px;height:250px;overflow:scroll-y;padding:10px;">
	<div id="conversation"></div>
	<input id="data" style="awidth:200px;" />
	<input type="button" id="datasend" value="send" />
</div>
0