nowjs和nodejs实现服务器端与客户端实时数据传输的例子
参考:http://www.bennadel.com/blog/2171-Realtime-Messaging-And-Synchronization-With-NowJS-And-Node-js.htm
先说例子实现的功能。网页上有一图片,图片可以拖动。用浏览器打开多个同一网页,当图片移动时,其它页面的图片会同步移动。例子也展示了用jQuery实现图片的拖动。
测试环境window7,nodejs v0.6.5 分别用ie,firefox,chrome打开http://127.0.0.1:8080/client.html,所有该网页上的图片会同步移动。贴上代码。
server.js端:
需要用sock.io和nowjs第三包,推荐用npm方式安装。nowjs包在window的安装可参考:
http://blog.nowjs.com/running-nowjs-natively-on-windows
// Include the necessary modules.var sys = require("util");var http = require("http");var url = require("url");var path = require("path");var fileSystem = require("fs");// ---------------------- //// ---------------------- //// Create an instance of the HTTP server.var server = http.createServer( function (request, response) {// Get the requested "script_name". This is the part of the// path after the server_name. var scriptName = request.url;// Convert the script name (expand-path) to a physical file// on the local file system. var requestdFilePath = path.join(process.cwd(), scriptName);// Read in the requested file. Remember, since all File I/O// (input and output) is asynchronous in Node.js, we need to// ask for the file to be read and then provide a callback// for when that file data is available.//// NOTE: You can check to see if the file exists *before* you// try to read it; but for our demo purposes, I don't see an// immediate benefit since the readFile() method provides an// error object. fileSystem.readFile( requestdFilePath, "binary", function (error, fileBinary) {// Check to see if there was a problem reading the// file. If so, we'll **assume** it is a 404 error. if (error) {// Send the file not found header. response.writeHead(404);// Close the response. response.end();// Return out of this guard statement. return; }// If we made it this far then the file was read in// without a problem. Set a 200 status response. response.writeHead(200);// Serve up the file binary data. When doing this, we// have to set the encoding as binary (it defaults to// UTF-8). response.write(fileBinary, "binary");// End the response. response.end(); } ); });// Point the server to listen to the given port for incoming// requests.server.listen(8080);// ---------------------- //// ---------------------- //// Create a local memory space for further now-configuration.(function () {// Now that we have our HTTP server initialized, let's configure// our NowJS connector. var nowjs = require("now");// After we have set up our HTTP server to serve up "Static"// files, we pass it off to the NowJS connector to have it// augment the server object. This will prepare it to serve up// the NowJS client module (including the appropriate port// number and server name) and basically wire everything together// for us.//// Everyone contains an object called "now" (ie. everyone.now) -// this allows variables and functions to be shared between the// server and the client. var everyone = nowjs.initialize(server);// Create primary key to keep track of all the clients that// connect. Each one will be assigned a unique ID. var primaryKey = 0;// When a client has connected, assign it a UUID. In the// context of this callback, "this" refers to the specific client// that is communicating with the server.//// NOTE: This "uuid" value is NOT synced to the client; however,// when the client connects to the server, this UUID will be// available in the calling context. everyone.connected( function () { this.now.uuid = ++primaryKey; } );// Add a broadcast function to *every* client that they can call// when they want to sync the position of the draggable target.// In the context of this callback, "this" refers to the// specific client that is communicating with the server. everyone.now.syncPosition = function (position) {//syncPosition()在这里定义,在客户端调用// Now that we have the new position, we want to broadcast// this back to every client except the one that sent it in// the first place! As such, we want to perform a server-side// filtering of the clients. To do this, we will use a filter// method which filters on the UUID we assigned at connection// time. everyone.now.filterUpdateBroadcast(this.now.uuid, position); };// We want the "update" messages to go to every client except// the one that announced it (as it is taking care of that on// its own site). As such, we need a way to filter our update// broadcasts. By defining this filter method on the server, it// allows us to cut down on some server-client communication. everyone.now.filterUpdateBroadcast = function (masterUUID, position) {// Make sure this client is NOT the same client as the one// that sent the original position broadcast. if (this.now.uuid == masterUUID) {// Return out of guard statement - we don't want to// send an update message back to the sender. return; }// If we've made it this far, then this client is a slave// client, not a master client. this.now.updatePosition(position);//updatePosition()为客户端定义的方法,在这里可调用,用this修饰now。 };})();// ---------------------- //// ---------------------- //// Write debugging information to the console to indicate that// the server has been configured and is up and running.sys.puts("Server is running on 8080");<!DOCTYPE html><html><head> <title>NowJS And Node.js Realtime Communication</title> <style type="text/css"> html, body { height: 100%; overflow: hidden; width: 100%; } img { left: 9px; position: absolute; top: 70px; } </style> <!-- We have this file stored explicitly. --> <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"/> </script> <!-- The NowJS HTTP augmentation will take care of routing this - we don't actually have this physical file stored at this file path. --> <script type = "text/javascript" src = "/nowjs/now.js" ></script></head><body><h1> NowJS And Node.js Realtime Communication</h1><!--This will be draggable. When this image drags, we aregoing to sync the position of it across browsers.--><img id="myhead" src="./myhead.gif" width="100" height="100" alt="nowjs跟nodejs实现服务器端与客户端实时数据传输的例子" /><!-- Configure the client-side script. --><script type="text/javascript"> // Get a reference to the target draggable. var myhead = $("#myhead"); // Get a reference to the body - this is the element on which // we'll be tracking mouse movement once the draggable // tracking has been turned on. var body = $("body"); // On mouse-down, turn on draggability. myhead.mousedown( function (event) {// Prevent the default behavior. event.preventDefault();// Get the current position of the mouse within the// bounds of the target. var localOffset = { x:(event.pageX - myhead.position().left), y:(event.pageY - myhead.position().top) };// Start tracking the mouse movement on the body.// We're tracking on the body so that the mouse can// move faster than the tracking. body.mousemove( function (event) {// Create a new position object. var newPosition = { left:(event.pageX - localOffset.x), top:(event.pageY - localOffset.y) };// Update the target position locally. myhead.css(newPosition);// Announce the updated position so that we// can sync accross all clients with NowJS. now.syncPosition(newPosition);//syncPosition()是在服务器端定义的方法,可在客户端调用。 } ); } ); // On mouse-up, turn off draggability. myhead.mouseup( function (event) {// Unbind the mousemove - no need to track movement// once the mouse has been lifted. body.unbind("mousemove"); } ); // I allow the remove server to make a request to update the // position of the target. // // NOTE: By defining this function in the NOW scope, it gives // the server access to it as well. now.updatePosition = function (newPosition){//updatePosition()这个方法在客户端定义,可在服务器端调用// Check to see if this client is in master mode; if so,// we won't update the position as this client is// actively updating its own position. myhead.css(newPosition); };</script></body></html>