วันพุธที่ 30 เมษายน พ.ศ. 2557

HTML5 : node.js and WebSocket - Part 2 socket.io and sayHello


Socket.io เป็น module ที่ช่วยในการทำ WebSocket ซึ่งเป็น tcp อ้างเชื่อมต่อจะต้องมี weburl และ port
ซึ่งใน module ก็มีทั้งฝั่ง client และ server

ส่วน server จะผูกกับ node.js ที่เราได้ตั้ง path ไว้เรียบร้อยแล้วใน part1 ซึ่งสามารถเรียกใช้ได้ทันที

ส่วน client เราต้องนำ javascript ไฟล์ที่อยู่ใน module ถ้าเครื่องผมจะอยู่ที่ E:\Program Files\nodejs\node_modules\npm\node_modules\socket.io\node_modules\socket.io-client\dist

ซึ่งมีอยู่ 2 ไฟล์ socket.io.js และ socket.io.min.js ซึ่งสามารถเลือกเอาไปใช้ได้ครับ .min แค่บีบอัดแล้วครับทำให้ไฟล์เล็กลง

ใน โฟลเดอร์ socket.io-client มีโฟลเดอร์ test ให้ด้วยนะครับเป็นตัวอย่างโค้ดให้เรานำเอาไปประยุกต์ต่อได้ครับ

เข้าเนื้อหาวันนี้กัน
- main entrance ของ client ครับ ใครติดต่อเข้ามาก็จะเข้ามาที่นี่ก่อนเลย ซึ่ง socket ที่ได้มาคือ clent socket ไว้สำหรับใช้ในการอ้างอิงเพื่อส่งข้อมูลกลับไปหา client ได้ครับ

socketio.listen(server).on('connection', function(socket){
   
}


ในการรับส่งข้อมูลเราจะใช้ผ่าน object ของ socket ครับ ซึ่งมี 2 method หลักๆ

- socket.on เป็น listener method สำหรับรอรับข้อมูลที่ส่งมาจาก client ซึ่งรับชื่อสำหรับการติดต่อ ตามตัวอย่างคือ sayHello และ ข้อมูลที่ได้รับมา

ตัวอย่าง
socket.on('sayHello', function (data) {
    console.log("sayHello = " + data);
    socket.emit("sayHello","Hello " + data); // send back to client
});


- socket.emit ใช้สำหรับส่งค่าไปยัง listener ที่เราสร้างไว้  ซึ่งใช้ทั้ง client และ server เหมือนกัน
ตัวอย่าง

socket.emit("sayHello","Piti"); // client ส่งค่า Piti ไปยัง on("sayHello") ที่ได้สร้างไว้

- socket.broadcast.emit ใช้ในการส่งหาทุก socket ยกเว้น socket ของคนส่งครับ ถ้าอยากส่งให้คนส่งด้วยก็ต้อง socket.emit ของตัวเองเพิ่มอีกหนึ่งอันครับ

--------------------------------------------------------------------------------------

มาภาคปฏิบัติครับ

//----------- Server Side ---------------//

// part2/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 sockets = new Array();

socketio.listen(server).on('connection', function(socket){
        sockets.push(socket);
       
        socket.on('sayHello', function (data) {
            console.log("sayHello = " + data);
            socket.emit("sayHello","Hello " + data); // send back to client
        });
       
        socket.on('sayGoodBye', function (data) {
            console.log("sayGoodBye = " + data);
            socket.emit("sayGoodBye","GoodBye " + data); // send back to client
        });
       
        socket.on('sayToAll', function (msg) {
                console.log('message received', msg);
               
                // send back to all client
                socket.broadcast.emit('sayToAll', msg);
                socket.emit('sayToAll', msg);
        });
});

//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);
}
// end  part2/server.js


//----------- Client Side ---------------//
อย่าลืมเอา socket.io.js ที่เป็น client script มาใส่ใน project ด้วยนะครับ
ผมใช้ WebWorker มาใช้นะครับ เผื่อจะใช้ร่วมกันหลายหน้า จะได้เปลี่ยนเป็น shared worker ได้ทันทีครับ


//----------------  part2/worker.js
importScripts('js/socket.io.js');
var socket;
self.onmessage = function (ev) {
   
      var data = ev.data;
    switch (data.cmd) {
       
  // connect
    case 'connect':
    {
        //self.postMessage("Client Connect ");
        self.postMessage({'type': 'status', 'msg': 'Client Connect '});
       
        var url = data.msg;
         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 sayHello send back from server
      socket.on('sayHello', function (data) {
        self.postMessage({'type': 'sayHello', 'msg': data}); // send from worker to web page
      });

      // listener sayGoodBye send back from server
      socket.on('sayGoodBye', function (data) {
        self.postMessage({'type': 'sayGoodBye', 'msg': data}); // send from worker to web page
      });

      // listener sayToAll send back from server
      socket.on('sayToAll', function (data) {
        self.postMessage({'type': 'sayToAll', '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  'sayHello':
            socket.emit('sayHello',data.msg);
    break;
   
    // send to Server
    case  'sayGoodBye':
            socket.emit('sayGoodBye',data.msg);
    break;

    // send to Server
    case  'sayToAll':
            socket.emit('sayToAll',data.msg);
    break;
   
   
    default:
      //self.postMessage('Unknown command: ' + data.msg);
  };

}
// end worker.js

//----------------  part2/client.php
<!DOCTYPE HTML>
<html>
<head>
<title>NodeJS Part 2</title>

<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+"<br/>";
            break;
        case 'data'  :
        ;
        break;
        case 'sayHello'  :
            document.getElementById('response').innerHTML = data.msg;
        break;

        case 'sayGoodBye'  :
            document.getElementById('response').innerHTML = data.msg;
        break;

        case 'sayToAll'  :
            document.getElementById('responseBroadcast').innerHTML = document.getElementById('responseBroadcast').innerHTML + data.msg +"<br/>";
        break;

    };


};

function sayHello(){
    var name = document.getElementById('name').value;
    var user = new Object();
    user.name = name;
    worker.postMessage({'cmd': 'sayHello', 'msg': JSON.stringify(user)});
}

function sayGoodBye(){
    var name = document.getElementById('name').value;
    var user = new Object();
    user.name = name;
    worker.postMessage({'cmd': 'sayGoodBye', 'msg': JSON.stringify(user)});
}

function sayToAll(){
    var name = document.getElementById('name').value;
    worker.postMessage({'cmd': 'sayToAll', 'msg': name});
}


function connect(){
worker.postMessage({'cmd': 'connect', 'msg': '127.0.0.1:1333'}); // connect at 127.0.0.1:1333
}

function disconnect(){
worker.postMessage({'cmd': 'disconnect', 'msg': ''});
}


// connect server at start up
connect();
</script>

</head>
<body>
<p>Status: <span id="result" /></p>

<!--
<input onclick="connect()" type="button" value="Connect" /> <input onClick="disconnect();" type="button" value="Disconnect" />
-->
<br/><br/>
Name : <input type="text" id="name" name="name" /> <br/>
<input onClick="sayHello();" type="button" value="Say Hello"/> <input onClick="sayGoodBye();" type="button" value="Say GoodBye"/> <input onClick="sayToAll();" type="button" value="Say To All"/>

<br/>
<br/>
Response : <br/>
<span id="response"></span>
<br/>
<br/>

Response Broadcast : <br/>
<span id="responseBroadcast"></span>
</body>
</html>
// end client.php



//------------------- Running -----------------//
อย่าลืมเปิด server ด้วยคำสั่ง node server.js นะครับ




อ้างอิง http://socket.io/

วันอังคารที่ 29 เมษายน พ.ศ. 2557

HTML5 : node.js and WebSocket - Part 1 Installation and setup


node.js คือ โปรแกรมที่รันบน server-side แต่เขียนด้วย javascript ซึ่งถูกรันด้วย Java Script Engine ของ Google
ความสามารถเบื้องต้น
สามารถตั้งตนเป็น HTTP Server และเปิด Socket ได้ แต่จริงๆ ยังมีอีกหลายอย่างนะครับ ขอ scope แค่นี้ก่อน

ซึ่งผมจะเน้นในการเปิด Socket เพื่อใช้ทำ WebSocket ตาม standard ของ HTML5 เป็นหลักครับ
Mission Start

Mission 1 -> Install node.js
http://nodejs.org/
ผมใช้ node-v0.10.26-x64.msi เป็นตัวติดตั้งครับ (เครื่องผมเป็น Window)
จากนั้นก็ install จนเสร็จ
มาดูโครงสร้างกัน
 

ใน nodejs มี

- npm.cmd เป็นพระเอกในการจัดการ module ต่างๆ ผมเดาว่าย่อมาจาก node package manager ผมคิดเองนะครับ 555 ตัวอย่างคำสั่ง npm install socket.io

- node.exe ใช้ในการรัน script ที่เราเขียนไว้นะครับ เช่น node server.js

- โฟลเดอร์ node_modules สังเกตว่าจะมีสองที่ครับคืออยู่ที่ root แล้วอยู่ใน npm อีกที ส่วนตัวผมเวลา install module ใหม่ ผมจะลงไปใน node_modules ของ npm เลยครับ จะได้อ้างที่เดียว เห็นมี module อื่นอยู่เยอะดีครับ

Mission 2 -> setup environment
สร้าง environment variable ชื่อ NODE_PATH ให้มีค่า
E:\Program Files\nodejs\node_modules\npm\node_modules นี่เครื่องผมครับ ใครลงตรงไหนก็ปรับไปละกันครับ ซึ่ง NODE_PATH

ตัว node.js จะใช้ในการอ้างไปยัง module ที่เราจะเรียกใช้ครับ ดังนั้นหากเราใส่ module เข้าไปที่โฟลเดอร์นี้ เราก็จะสามารถอ้างถึง module ที่ลงใหม่ได้ทันทีครับ



Mission 3 -> มาลง module ที่จำเป็นกันเถอะครับ
module ของ node.js มีเยอะแยะครับ ต่อ database ต่อ websocket และ utility ต่างๆ ครับ ที่เราจะใช้งานคือ socket.io และ formidable

เข้า command line ครับ จากนั้น ไปที่ E:\Program Files\nodejs\node_modules\npm
- รัน npm install socket.io
- รัน npm install formidable

ปล. ลงแล้วไปเช็คใน node_modules ว่ามี socket.io เพิ่มมารึเปล่านะครับ ถ้ามีก็โอเคครับ ถ้าลงผิดที่ก็ลบ socket.io ตัวที่ผิดแล้วรันใหม่ได้เลยครับ เป็นการการ download script มาไว้ในเครื่องเฉยๆ ไม่ต้องหา uninstall ครับ


ใครอยากรู้ว่ามีคำสั่งอะไรบ้างลอง npm help ได้นะครับ


Last Mission -> test
มาสร้างไฟล์ทดสอบกันครับ

// hello_world.js
var http = require('http');
http.createServer(function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
}).listen(1333, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1333/');

โอเค นี่คือการทำ Hello World แบบฉบับ node.js ครับ รันด้วย node hello_world.js
จากนั้นเปิด browser ครับแล้วพิมพ์ http://127.0.0.1:1333/ คุณก็ได้จะได้ Hello World ดังใจ



Trick
ในการรันเราสามารถสร้าง .bat มาใช้ได้ครับเพื่อสะดวกในการรัน

// hello_world.bat ไว้ที่เดียวกับ hello_world.js ครับ
node hello_world.js

เวลารันก็แค่คลิก hello_world.bat ก็เรียบร้อย