加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

nodejs实现服务器端与客户端实时数据传输的例子

(2016-05-28 11:29:08)
参考: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 
  1. // Include the necessary modules.  
  2. var sys require("util");  
  3. var http require("http");  
  4. var url require("url");  
  5. var path require("path");  
  6. var fileSystem require("fs");  
  7.   
  8.   
  9. // ---------------------------------------------------------- //  
  10. // ---------------------------------------------------------- //  
  11.   
  12.   
  13. // Create an instance of the HTTP server.  
  14. var server http.createServer(  
  15.     function (request, response)  
  16.   
  17. // Get the requested "script_name". This is the part of the  
  18. // path after the server_name.  
  19.         var scriptName request.url;  
  20.   
  21. // Convert the script name (expand-path) to physical file  
  22. // on the local file system.  
  23.         var requestdFilePath path.join(process.cwd(), scriptName);  
  24.   
  25. // Read in the requested file. Remember, since all File I/O  
  26. // (input and output) is asynchronous in Node.js, we need to  
  27. // ask for the file to be read and then provide callback  
  28. // for when that file data is available.  
  29. //  
  30. // NOTE: You can check to see if the file exists *before* you  
  31. // try to read it; but for our demo purposes, don't see an  
  32. // immediate benefit since the readFile() method provides an  
  33. // error object.  
  34.         fileSystem.readFile(  
  35.             requestdFilePath,  
  36.             "binary" 
  37.             function (error, fileBinary)  
  38.   
  39. // Check to see if there was problem reading the  
  40. // file. If so, we'll **assume** it is 404 error.  
  41.                 if (error)  
  42.   
  43. // Send the file not found header.  
  44.                     response.writeHead(404);  
  45.   
  46. // Close the response.  
  47.                     response.end();  
  48.   
  49. // Return out of this guard statement.  
  50.                     return 
  51.   
  52.                  
  53.   
  54. // If we made it this far then the file was read in  
  55. // without problem. Set 200 status response.  
  56.                 response.writeHead(200);  
  57.   
  58. // Serve up the file binary data. When doing this, we  
  59. // have to set the encoding as binary (it defaults to  
  60. // UTF-8).  
  61.                 response.write(fileBinary, "binary");  
  62.   
  63. // End the response.  
  64.                 response.end();  
  65.   
  66.              
  67.         );  
  68.   
  69.      
  70. );  
  71.   
  72. // Point the server to listen to the given port for incoming  
  73. // requests.  
  74. server.listen(8080);  
  75.   
  76.   
  77. // ---------------------------------------------------------- //  
  78. // ---------------------------------------------------------- //  
  79.   
  80.   
  81. // Create local memory space for further now-configuration.  
  82. (function ()  
  83.   
  84. // Now that we have our HTTP server initialized, let's configure  
  85. // our NowJS connector.  
  86.     var nowjs require("now");  
  87.   
  88.   
  89. // After we have set up our HTTP server to serve up "Static"  
  90. // files, we pass it off to the NowJS connector to have it  
  91. // augment the server object. This will prepare it to serve up  
  92. // the NowJS client module (including the appropriate port  
  93. // number and server name) and basically wire everything together  
  94. // for us.  
  95. //  
  96. // Everyone contains an object called "now" (ie. everyone.now) -  
  97. // this allows variables and functions to be shared between the  
  98. // server and the client.  
  99.     var everyone nowjs.initialize(server);  
  100.   
  101.   
  102. // Create primary key to keep track of all the clients that  
  103. // connect. Each one will be assigned unique ID.  
  104.     var primaryKey 0;  
  105.   
  106.   
  107. // When client has connected, assign it UUID. In the  
  108. // context of this callback, "this" refers to the specific client  
  109. // that is communicating with the server.  
  110. //  
  111. // NOTE: This "uuid" value is NOT synced to the client; however,  
  112. // when the client connects to the server, this UUID will be  
  113. // available in the calling context.  
  114.     everyone.connected(  
  115.         function ()  
  116.             this.now.uuid ++primaryKey;  
  117.          
  118.     );  
  119.   
  120.   
  121. // Add broadcast function to *every* client that they can call  
  122. // when they want to sync the position of the draggable target.  
  123. // In the context of this callback, "this" refers to the  
  124. // specific client that is communicating with the server.  
  125.     everyone.now.syncPosition function (position) {//syncPosition()在这里定义,在客户端调用  
  126.   
  127. // Now that we have the new position, we want to broadcast  
  128. // this back to every client except the one that sent it in  
  129. // the first place! As such, we want to perform server-side  
  130. // filtering of the clients. To do this, we will use filter  
  131. // method which filters on the UUID we assigned at connection  
  132. // time.  
  133.         everyone.now.filterUpdateBroadcast(this.now.uuid, position);  
  134.   
  135.     };  
  136.   
  137.   
  138. // We want the "update" messages to go to every client except  
  139. // the one that announced it (as it is taking care of that on  
  140. // its own site). As such, we need way to filter our update  
  141. // broadcasts. By defining this filter method on the server, it  
  142. // allows us to cut down on some server-client communication.  
  143.     everyone.now.filterUpdateBroadcast function (masterUUID, position)  
  144.   
  145. // Make sure this client is NOT the same client as the one  
  146. // that sent the original position broadcast.  
  147.         if (this.now.uuid == masterUUID)  
  148.   
  149. // Return out of guard statement we don't want to  
  150. // send an update message back to the sender.  
  151.             return 
  152.   
  153.          
  154.   
  155. // If we've made it this far, then this client is slave  
  156. // client, not master client.  
  157.         this.now.updatePosition(position);//updatePosition()为客户端定义的方法,在这里可调用,用this修饰now。  
  158.   
  159.     };  
  160.   
  161. })();  
  162.   
  163.   
  164. // ---------------------------------------------------------- //  
  165. // ---------------------------------------------------------- //  
  166.   
  167.   
  168. // Write debugging information to the console to indicate that  
  169. // the server has been configured and is up and running.  
  170. sys.puts("Server is running on 8080");  


我把重要的东西摘录下来: 
引用
Once the core HTTP server is configured and the NowJS module is initialized, we are given access to the "everyone" object. This everyone object then provides us with access to the server-side "now" scope. This "now" scope is shared between the server and every one of the clients. Anything added to or removed from the server-side "now" scope is also added to or removed from every client currently (or eventually) connected to the server. 

This is true for both variables and functions! Notice that my server-side Node.js code defines two methods: syncPosition() and filterUpdateBroadcast(). By defining them in the "everyone.now" scope, I am making them available to both the server and to every single one of the connected clients. 

But what about that, "everyone.now.updatePosition()", function? Where did that come from? Ah-ha! Here's the real, "there is no spoon" mind-screw - that function is defined on the client (which we'll see in a minute). And, since it's defined in the client's "now" scope, the server-side Javascript can then invoke it as if there were no separation between the server and client contexts.


client.html 
  1. >  
  2.   
  3.         html,  
  4.         body  
  5.             height: 100%;  
  6.             overflow: hidden;  
  7.             width: 100%;  
  8.          
  9.   
  10.         img  
  11.             left: 9px;  
  12.             position: absolute;  
  13.             top: 70px;  
  14.          
  15.   
  16.     </</span>style>  
  17.   
  18.       
  19.     <</span>script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"/>  
  20.     </</span>script>  
  21.   
  22.       
  23. <</span>script type="text/javascript">  
  24.   
  25.     // Get reference to the target draggable.  
  26.     var myhead $("#myhead");  
  27.   
  28.     // Get reference to the body this is the element on which  
  29.     // we'll be tracking mouse movement once the draggable  
  30.     // tracking has been turned on.  
  31.     var body $("body");  
  32.   
  33.   
  34.     // On mouse-down, turn on draggability.  
  35.     myhead.mousedown(  
  36.             function (event)  
  37. // Prevent the default behavior.  
  38.                 event.preventDefault();  
  39.   
  40. // Get the current position of the mouse within the  
  41. // bounds of the target.  
  42.                 var localOffset  
  43.                     x:(event.pageX myhead.position().left),  
  44.                     y:(event.pageY myhead.position().top)  
  45.                 };  
  46.   
  47. // Start tracking the mouse movement on the body.  
  48. // We're tracking on the body so that the mouse can  
  49. // move faster than the tracking.  
  50.                 body.mousemove(  
  51.                         function (event)  
  52. // Create new position object.  
  53.                             var newPosition  
  54.                                 left:(event.pageX localOffset.x),  
  55.                                 top:(event.pageY localOffset.y)  
  56.                             };  
  57.   
  58. // Update the target position locally.  
  59.                             myhead.css(newPosition);  
  60.   
  61. // Announce the updated position so that we  
  62. // can sync accross all clients with NowJS.  
  63.                             now.syncPosition(newPosition);//syncPosition()是在服务器端定义的方法,可在客户端调用。  
  64.                          
  65.                 );  
  66.              
  67.     );  
  68.   
  69.   
  70.     // On mouse-up, turn off draggability.  
  71.     myhead.mouseup(  
  72.             function (event)  
  73. // Unbind the mousemove no need to track movement  
  74. // once the mouse has been lifted.  
  75.                 body.unbind("mousemove");  
  76.              
  77.     );  
  78.   
  79.   
  80.     // allow the remove server to make request to update the  
  81.     // position of the target.  
  82.     //  
  83.     // NOTE: By defining this function in the NOW scope, it gives  
  84.     // the server access to it as well.  
  85.     now.updatePosition function (newPosition){  
  86. //updatePosition()这个方法在客户端定义,可在服务器端调用  
  87. // Check to see if this client is in master mode; if so,  
  88. // we won't update the position as this client is  
  89. // actively updating its own position.  
  90.         myhead.css(newPosition);  
  91.   
  92.     };  
  93.   
  94. </</span>script>  
  95. </</span>body>  
  96. </</span>html>  


引用
When the user moves the image on the client, the client broadcasts the new position using the "now.syncPosition()" function. This function, which was defined on the server, then pushes the updated position down to all the other clients using the "now.updatePosition()" function, which was defined on the client. 

Even after coding this myself, it's still somewhat confusing; so, let's look at a quick rundown of the various functions to see where they were defined and where they were invoked: 

syncPosition() 
  • Defined: Server-side
  • Invoked: Client-side

filterUpdateBroadcast() 
  • Defined: Server-side
  • Invoked: Server-side

updatePosition() 
  • Defined: Client-side
  • Invoked: Server-side

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有