วันนี้ทำจริงจังครับ แต่แรงพอแค่สร้างส่วนจัดการห้อง เหมือนเกมออนไลน์เลยครับมี 3 ส่วน
1. ส่วนหน้า connect server
2. ส่วนหน้า Room List คือดูห้องที่เราจะเข้าไปอาศัย แล้วก็สามารถสร้างห้องของตัวเองได้ครับ
3. ส่วนหน้า Room Waiting คือหน้าที่เราเข้าห้องแล้วรอเล่นเกมนะครับ
ขอไม่อธิบายโค้ดละเอียดนะครับ เยอะมาก เอาไปลองรันเล่นกันได้เลยครับ ใครที่อ่านโค้ดไม่รู้เรื่องให้อ่าน part1 ,part2, part3 ก่อนครับ แล้วก็จะอ่านของตอนนี้รู้เรื่องครับ ขอให้ความรู้อยู่คู่ทุกคนครับ 555
-------------------------------------------------------------------------
โค้ดๆ
ฝั่ง server มีพระเอก 3 ตัวครับ
socket ทุกคนคงรู้จักแล้ว เป็น socket ใช้ในการติดต่อหากันระหว่า client กับ server
user ผมใช้เป็นตัวแทน user ครับ ตอนนี้มี 3 field คือ socketId(ไว้อ้างอิงเพื่อดึง socket), name, roomId(ใช้ระบุว่า user นี้อยู่ห้องไหน หากไม่ได้อยู่จะเป็น null)
room เป็นตัวแทนห้องครับ ถูกสร้างเมื่อ create ครับใครมา join ก็รับเอา roomId ไปใส่ให้ user ได้เลยครับ
-- การไล่โค้ด --
แบ่งเป็น 2 ส่วนโดยคั่นกลางด้วย Listener method นั่นก็คือ socketio.listen(server).on('connection' นั่นเอง
- โดย function ที่อยู่ด้านบนจะเป็นส่วนที่ listener เรียกใช้
- และ function ที่อยู่ด้านล่างจะเป็นส่วนจัดการข้อมูลเรียกว่าเป็น utility function ละกันครับ
// practical1/server.js
var http = require('http');
var formidable = require("formidable");
var socketio = require('socket.io');
var server = http.createServer(function(req, res) {
form = new formidable.IncomingForm();
form.parse(req, function(e, fields, files){
res.writeHead(200, [['Content-type','text/plain'],['Content-Length',0]]);
res.write('');
res.end();
//Handle sending data back through the socket to the web client
handleServerNotice(fields);
});
}).listen(1333, function() {
console.log('listening on 1333');
});
var RoomStatusEnum = { WAITING: 1, PLAYING: 2 };
if(Object.freeze){
Object.freeze(RoomStatusEnum);
}
var sockets = new Array();
var users = new Array();
var rooms = new Array();
function registerUser(socketId,name){
var user = new Object();
user.socketId = socketId;
user.name = name;
user.roomId = null;
users.push(user);
var socket = socketManage.getSocket(socketId);
socket.emit("registerUser",JSON.stringify(user));
userList();
roomList();
}
function disconnectUser(socketId){
var user = userManage.getUser(socketId);
console.log('disconnectUser = ' + JSON.stringify(user));
for(var i=0;i<users.length;i++){
var queryuser = users[i];
var socket = socketManage.getSocket(queryuser.socketId);
if(socket != null){
socket.emit("disconnectUser",JSON.stringify(user));
}
}
if(user.roomId != null){
leaveRoom(user.roomId);
}
userManage.removeUser(socketId);
socketManage.removeSocket(socketId);
userList();
}
function userList(){
for(var i=0;i<users.length;i++){
var user = users[i];
var socket = socketManage.getSocket(user.socketId);
if(socket != null){
socket.emit("userList",JSON.stringify(users));
}
}
}
function createRoom(socket,roomName){
var room = new Object();
room.id = socket.manager.generateId();
room.name = roomName;
var user = userManage.getUser(socket.id);
room.ownerId = user.socketId;
room.ownerName = user.name;
room.status = RoomStatusEnum.WAITING;
user.roomId = room.id;
rooms.push(room);
var socket = socketManage.getSocket(user.socketId);
socket.emit("createRoom",JSON.stringify(room));
//updateRoom(room.id); // update room status
roomList(); // notify user outside room
userRoomList(socket,room.id); // notify user inside room
}
function joinRoom(socket,roomId){
var room = roomManage.getRoom(roomId);
var user = userManage.getUser(socket.id);
user.roomId = room.id;
var socket = socketManage.getSocket(user.socketId);
socket.emit("joinRoom",JSON.stringify(room));
//updateRoom(room.id); // update room status
userRoomList(socket,room.id); // notify user inside room
}
function leaveRoom(socket,roomId){
var room = roomManage.getRoom(roomId);
var user = userManage.getUser(socket.id);
// leave
user.roomId = null;
var userRooms = userManage.getUserRoom(roomId);
// no anybody in room
if(userRooms.length == 0){
roomManage.removeRoom(roomId);
}else{
// user is owner then grant the next user to be the next owner and update room status
if(room.ownerId == user.socketId){
room.ownerId = userRooms[0].socketId;
room.ownerName = userRooms[0].name;
updateRoom(roomId);
}
}
var socket = socketManage.getSocket(user.socketId);
socket.emit("leaveRoom",JSON.stringify(user));
userRoomList(socket,room.id); // notify user inside room
roomList();
}
function updateRoom(roomId){
var room = roomManage.getRoom(roomId);
var userRooms = userManage.getUserRoom(roomId);
for(var i=0;i<userRooms.length;i++){
var userRoom = userRooms[i];
var socket = socketManage.getSocket(userRoom.socketId);
if(socket != null){
socket.emit("updateRoom",JSON.stringify(room));
}
}
}
function roomList(){
for(var i=0;i<users.length;i++){
var user = users[i];
// send to user that not in the room
if(user.roomId == undefined || user.roomId == null){
var socket = socketManage.getSocket(user.socketId);
if(socket != null){
socket.emit("roomList",JSON.stringify(rooms));
}
}
}
}
/**
show user in the room
*/
function userRoomList(socket,roomId){
var userRooms = userManage.getUserRoom(roomId);
for(var i=0;i<userRooms.length;i++){
var userRoom = userRooms[i];
var socket = socketManage.getSocket(userRoom.socketId);
if(socket != null){
socket.emit("userRoomList",JSON.stringify(userRooms));
}
}
}
// Listener method
socketio.listen(server).on('connection', function(socket){
console.log("generatedId = " + socket.manager.generateId());
sockets.push(socket);
socket.on('registerUser', function (data) {
console.log(socket.id + " registerUser = " + data);
var user = JSON.parse(data);
registerUser(socket.id,user.name);
});
socket.on('userList', function (data) {
userList();
});
socket.on('createRoom', function (data) {
var room = JSON.parse(data);
createRoom(socket,room.name);
});
socket.on('joinRoom', function (data) {
var room = JSON.parse(data);
joinRoom(socket,room.id);
});
socket.on('leaveRoom', function (data) {
var room = JSON.parse(data);
//console.log("leaveRoom = " +data);
leaveRoom(socket,room.id);
});
socket.on('roomList', function (data) {
roomList();
});
socket.on('userRoomList', function (data) {
var room = JSON.parse(data);
userRoomList(room.id);
});
socket.on('disconnect', function(data){
console.log('disconnect socket id', socket.id);
disconnectUser(socket.id);
//socketManage.removeSocket(socket.id);
});
});
/***************************************************************************
User Manage
****************************************************************************/
var userManage = new Object();
/**
@Description
find socket index by socketId
@Return
index of Socket in sockets array
**/
userManage.getUserIndex = function(socketId){
var selectIndex = -1;
for(var i=0;i<users.length;i++){
var user= users[i];
if(user.socketId == socketId){
selectIndex = i;
break;
}
}
return selectIndex;
};
/**
@Description
find user in the room
@Return
all user in the room
**/
userManage.getUserRoom = function(roomId){
var userRooms = new Array();
for(var i=0;i<users.length;i++){
var user= users[i];
if(user.roomId == roomId){
userRooms.push(user);
}
}
return userRooms;
};
/**
@Description
get socket by socketId
@Return
Socket or null if not found
**/
userManage.getUser = function(socketId){
var selectIndex = userManage.getUserIndex(socketId);
if(selectIndex != -1){
return users[selectIndex];
}else{
return null;
}
};
/**
@Description
remove socket by socketId
**/
userManage.removeUser = function(socketId){
var selectIndex = userManage.getUserIndex(socketId);
if(selectIndex != -1){
users.splice(selectIndex,1);
}
};
/***************************************************************************
Room Manage
****************************************************************************/
var roomManage = new Object();
/**
@Description
find room index by roomId
@Return
index of room in rooms array
**/
roomManage.getRoomIndex = function(roomId){
var selectIndex = -1;
for(var i=0;i<rooms.length;i++){
var room= rooms[i];
if(room.id == roomId){
selectIndex = i;
break;
}
}
return selectIndex;
};
/**
@Description
get room by roomId
@Return
Room or null if not found
**/
roomManage.getRoom = function(roomId){
var selectIndex = roomManage.getRoomIndex(roomId);
if(selectIndex != -1){
return rooms[selectIndex];
}else{
return null;
}
};
/**
@Description
remove socket by socketId
**/
roomManage.removeRoom = function(roomId){
var selectIndex = roomManage.getRoomIndex(roomId);
if(selectIndex != -1){
rooms.splice(selectIndex,1);
}
};
/***************************************************************************
Socket Manage
****************************************************************************/
var socketManage = new Object();
/**
@Description
find socket index by socketId
@Return
index of Socket in sockets array
**/
socketManage.getSocketIndex = function(socketId){
var selectIndex = -1;
for(var i=0;i<sockets.length;i++){
var socket = sockets[i];
if(socket.id == socketId){
selectIndex = i;
break;
}
}
return selectIndex;
};
/**
@Description
get socket by socketId
@Return
Socket or null if not found
**/
socketManage.getSocket = function(socketId){
var selectIndex = socketManage.getSocketIndex(socketId);
if(selectIndex != -1){
return sockets[selectIndex];
}else{
return null;
}
};
/**
@Description
remove socket by socketId
**/
socketManage.removeSocket = function(socketId){
var selectIndex = socketManage.getSocketIndex(socketId);
if(selectIndex != -1){
sockets.splice(selectIndex,1);
}
};
//Emit a message to the client that we received a blank message from the php script. (Via POST)
function handleServerNotice(data){
console.log("HTML Message Received: ", data);
}
//-------------------------- client -------------------//
// practical1/worker.js อันนี้สวยอยู่แล้วไม่ต้องบอกอะไร 55
importScripts('js/socket.io.js');
var socket;
var user;
var room;
var game;
self.onmessage = function (ev) {
var data = ev.data;
switch (data.cmd) {
// connect
case 'connect':
{
self.postMessage({'type': 'status', 'msg': 'Client Connect '});
user = null;
room = null;
game = null;
var url = data.msg;
if(socket != undefined){
socket.socket.connect();
}else{
socket = io.connect(url);
socket.on('done', function () {
self.postMessage({'type': 'status', 'msg': 'done!'});
});
socket.on('connect_failed', function () {
self.postMessage({'type': 'status', 'msg': 'connect failed'});
});
socket.on('error', function () {
self.postMessage({'type': 'status', 'msg': 'error'});
});
// listener registerUser send back from server
socket.on('registerUser', function (data) {
user = JSON.parse(data);
self.postMessage({'type': 'registerUser', 'msg': data});
});
// listener disconnectUser send back from server
socket.on('disconnectUser', function (data) {
var user = JSON.parse(data);
self.postMessage({'type': 'status', 'msg': 'disconnectUser '+user.name}); // send from worker to web page
});
// listener userList send back from server
socket.on('userList', function (data) {
self.postMessage({'type': 'userList', 'msg': data}); // send from worker to web page
});
socket.on('updateRoom', function (data) {
room = JSON.parse(data);
self.postMessage({'type': 'updateRoom', 'msg': data});
});
socket.on('createRoom', function (data) {
room = JSON.parse(data);
self.postMessage({'type': 'createRoom', 'msg': data});
});
socket.on('joinRoom', function (data) {
room = JSON.parse(data);
self.postMessage({'type': 'joinRoom', 'msg': data});
});
socket.on('leaveRoom', function (data) {
//user = JSON.parse(data);
room = null;
self.postMessage({'type': 'leaveRoom', 'msg': data});
});
socket.on('roomList', function (data) {
self.postMessage({'type': 'roomList', 'msg': data}); // send from worker to web page
});
socket.on('userRoomList', function (data) {
self.postMessage({'type': 'userRoomList', 'msg': data}); // send from worker to web page
});
}
}
break;
// stop
case 'disconnect':
self.postMessage({'type': 'status', 'msg': 'Client Disconnect '});
socket.disconnect();
break;
// send to Server
case 'registerUser':
socket.emit('registerUser',data.msg);
break;
case 'createRoom':
socket.emit('createRoom',data.msg);
break;
case 'joinRoom':
socket.emit('joinRoom',data.msg);
break;
case 'leaveRoom':
socket.emit('leaveRoom',JSON.stringify(room));
break;
default:
//self.postMessage('Unknown command: ' + data.msg);
};
}
// practical1/client.php ผมใช้ jquery ด้วยนะครับ ใช้มี version ไหนอยู่ก็ใช้ได้เลยครับ
<!DOCTYPE HTML>
<html>
<head>
<title>NodeJS Practical1</title>
<script type="text/javascript" src="js/jquery_1.9.js"></script>
<script>
var worker = new Worker('worker.js');
worker.onmessage = function (event) {
//alert(event.data);
var data = event.data;
switch (data.type) {
case 'status' :
document.getElementById('result').innerHTML = document.getElementById('result').innerHTML+data.msg+"\r\n";
break;
case 'data' :
;
break;
case 'userList' :
var users = JSON.parse(data.msg);
var response = '';
for(var i=0;i<users.length;i++){
var user = users[i];
response += user.name+" ,socketId = " + user.socketId+"<br/>";
}
document.getElementById('response').innerHTML = response;
break;
case 'registerUser' :
{
var user = JSON.parse(data.msg);
document.getElementById('displayName').innerHTML = user.socketId + ' - ' +user.name;
// disable connectBtn
var connectBtn = document.getElementById('connectBtn');
var disconnectBtn = document.getElementById('disconnectBtn');
connectBtn.disabled = true;
disconnectBtn.disabled = false;
// go to room list step
document.getElementById('connectSection').style.display = 'none';
document.getElementById('roomSection').style.display = 'block';
break;
}
case 'createRoom' :
case 'joinRoom' :
{
var room = JSON.parse(data.msg);
$('#roomWaitingSection .roomName').html(room.id +' - '+room.name);
$('#roomWaitingSection .roomOwner').html(room.ownerId + ' - ' +room.ownerName);
// go to room waiting step
document.getElementById('roomSection').style.display = 'none';
document.getElementById('roomWaitingSection').style.display = 'block';
break;
}
case 'leaveRoom' :
{
document.getElementById('roomSection').style.display = 'block';
document.getElementById('roomWaitingSection').style.display = 'none';
break;
}
case 'roomList' :
{
var rooms = JSON.parse(data.msg);
roomSection.updateRoomList(rooms);
break;
}
case 'userRoomList' :
{
var userRooms = JSON.parse(data.msg);
roomSection.updateUserRoomList(userRooms);
break;
}
};
};
var roomSection = new Object();
// Room List
roomSection.templateRow = function(row,rowItem){
if(rowItem.id != undefined){
row.find('.roomId').text(rowItem.id+".");
}else{
row.find('.roomId').text("");
}
if(rowItem.name != undefined){
row.find('.roomName').text(rowItem.name);
}else{
row.find('.roomName').text("");
}
if(rowItem.ownerId != undefined){
row.find('.roomOwner').text(rowItem.ownerId +" - " + rowItem.ownerName);
}else{
row.find('.roomOwner').text("");
}
row.find('.joinBtn').attr('onclick',"roomSection.joinRoom('"+rowItem.id+"');");
row.addClass("table_row");
return row;
};
roomSection.updateRoomList = function(rooms){
var root = $('.roomList');
root.find('.table_row').remove();
for(var item = 0;item<rooms.length;item++ ){
var newRow = root.find('.template_row').clone().removeClass('template_row');
roomSection.templateRow(newRow,rooms[item]).appendTo(root).fadeIn();
}
};
// User Room List
roomSection.templateUserRoomRow = function(row,rowItem){
if(rowItem.socketId != undefined){
row.find('.userId').text(rowItem.socketId+".");
}else{
row.find('.userId').text("");
}
if(rowItem.name != undefined){
row.find('.userName').text(rowItem.name);
}else{
row.find('.userName').text("");
}
row.addClass("table_row");
return row;
};
roomSection.updateUserRoomList = function(userRooms){
var root = $('.userRoomList');
root.find('.table_row').remove();
for(var item = 0;item<userRooms.length;item++ ){
var newRow = root.find('.template_row').clone().removeClass('template_row');
roomSection.templateUserRoomRow(newRow,userRooms[item]).appendTo(root).fadeIn();
}
};
roomSection.createRoom = function(){
var roomName = document.getElementById('roomName').value;
if(roomName == ''){
alert("Please enter room name");
return;
}
var room = new Object();
room.name = roomName;
worker.postMessage({'cmd': 'createRoom', 'msg': JSON.stringify(room)});
};
roomSection.joinRoom = function(roomId){
var room = new Object();
room.id = roomId;
worker.postMessage({'cmd': 'joinRoom', 'msg': JSON.stringify(room)});
};
roomSection.leaveRoom = function(){
worker.postMessage({'cmd': 'leaveRoom', 'msg': ''});
};
function connect(){
var name = document.getElementById('name').value;
if(name == ''){
alert("Please enter your name");
return;
}
worker.postMessage({'cmd': 'connect', 'msg': '127.0.0.1:1333'}); // connect at 127.0.0.1:1333
var user = new Object();
user.name = name;
worker.postMessage({'cmd': 'registerUser', 'msg': JSON.stringify(user)});
}
function disconnect(){
worker.postMessage({'cmd': 'disconnect', 'msg': ''});
var connectBtn = document.getElementById('connectBtn');
var disconnectBtn = document.getElementById('disconnectBtn');
connectBtn.disabled = false;
disconnectBtn.disabled = true;
}
</script>
</head>
<body>
<div style="height:200px;">
<div style="float:left">
<p style="vertical-align:text-top">Server Status: <br/><textarea id="result" cols="80" rows="8" ></textarea></p>
</div>
<div style="float:right;width:400px;border:1px solid;height:150px;overflow:scroll">
User in Server : <br/>
<span id="response"></span>
</div>
</div>
<br/><br/>
<div>
<div id="displayName" style="font-weight:bold;color:blue"></div>
<br/>
<div id="connectSection">
Name : <input type="text" id="name" name="name" /> <br/>
<input onClick="connect();" type="button" name="connectBtn" id="connectBtn" value="Connect" />
<input onClick="disconnect();" type="button" name="disconnectBtn" id="disconnectBtn" value="Disconnect" disabled="disabled"/>
</div>
<div id="roomSection" style="display:none;">
<div style="font-weight:bold;color:blue">Room List Page</div>
<br/>
New Room : <input type="text" id="roomName" name="roomName" />
<input onClick="roomSection.createRoom();" type="button" name="createRoom" id="createRoom" value="Create Room" />
<br/><br/>
<table class="roomList" border="1" cellspacing="0">
<tr style="font-weight:bold;">
<td width="120" align="center">Room Id</td>
<td width="150" align="center">Room Name</td>
<td width="200" align="center">Room Owner</td>
<td width="80"> </td>
</tr>
<tr class="template_row" style="display:none">
<td class="roomId" align="left">1234567890</td>
<td class="roomName" align="left">Test</td>
<td class="roomOwner" align="left">12345678 - tester</td>
<td align="center"><input class="joinBtn" type="button" value="Join" style="width:60px;" /></td>
</tr>
</table>
</div>
<div id="roomWaitingSection" style="display:none;">
<div style="font-weight:bold;color:blue">Room Waiting Page</div>
<br/>
Room Name : <span class="roomName"></span>
<br/>
Room Owner : <span class="roomOwner"></span>
<br/><br/>
User :
<table class="userRoomList" border="1" cellspacing="0">
<tr style="font-weight:bold;">
<td width="120" align="center">User Id</td>
<td width="150" align="center">User Name</td>
</tr>
<tr class="template_row" style="display:none">
<td class="userId" align="left">1234567890</td>
<td class="userName" align="left">Test</td>
</tr>
</table>
<br/>
<input type="button" value="Start Game" /> <input type="button" value="Leave Room" onClick="roomSection.leaveRoom();"/>
</div>
</div>
</body>
</html>
สุดท้ายมารันกันครับ
อย่าลืม socket.io.js และ socket.io.min.js เอามาใส่ในโฟลเดอร์ js ด้วยนะครับ เอามาจาก module client ของ node.js นะครับ
รัน server ด้วย node server.js
ใครรันได้แล้วรู้เรื่องมากขึ้นก็แจ้งมาได้นะครับ 555
ชอบๆ ครับ แต่รัมไม่ขึ้น
ตอบลบ