Tìm hiểu cơ bản cách hoạt động của Socket Io bằng chat realtime
Bài đăng này đã không được cập nhật trong 2 năm
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;width: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;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width: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_bao và cap_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;width: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;width:300px;height:250px;overflow:scroll-y;padding:10px;">
<div id="conversation"></div>
<input id="data" style="width:200px;" />
<input type="button" id="datasend" value="send" />
</div>
All rights reserved