有人试过js通熊大熊二介绍的介绍吗

一,开篇分析
大家好啊,大熊君又来啦(*^__^*) 嘻嘻&&,之前我写过一系列关于方面的文章,反响还好,其实这也是对我本人最大的鼓励,于是我决定我要将JavaScript进行到底
准备写一个NodeJS方面的系列文章,由浅入深,循序渐进,秉承的理念是重思想,多实践,勤能补拙,贵在坚持。
我们先来看看NodeJS官网上的介绍:
  其特点为:
  1,它是一个Javascript运行环境
  2,依赖于Chrome V8引擎进行代码解释
  3,事件驱动
  4, 非阻塞I/O
  5, 轻量、可伸缩,适于实时数据交互应用
  6,单进程,单线程
  (1),Nodejs为什么选择javascript为载体语言
    事实上,在实现 Node.js 之初,作者 Ryan Dahl 并没有选择 JavaScript,他尝试过 C、Lua,皆因其欠缺一些高级语言的特性,如闭包、函数式编程,致使程序复杂,难以维护。
    而 JavaScript 则是支持函数式编程范型的语言,很好地契合了 Node.js 基于事件驱动的编程模型。加之 Google 提供的 V8 引擎,使 JavaScript 语言的执行速度大大提高。
    最终呈现在我们面前的就成了 Node.js,而不是 Node.c,Node.lua 或其他语言的实现。
  (2),Node.js不是JS应用、而是JS运行平台
    看到Node.js这个名字,初学者可能会误以为这是一个Javascript应用,事实上,Node.js采用C++语言编写而成,是一个Javascript的运行环境。
    Node.js采用了Google Chrome浏览器的V8引擎,性能很好,同时还提供了很多系统级的API,如文件操作、网络编程等。
    以下是NodeJS所涉及的全部模块:
    浏览器端的Javascript代码在运行时会受到各种安全性的限制,对客户系统的操作有限。
    相比之下,Node.js则是一个全面的后台运行时,为Javascript提供了其他语言能够实现的许多功能。
  (3),Node.js的特点
    Node.js在设计上也是比较创新,它以单进程,单线程模式运行(这和Javascript的运行方式是一致的),
    事件驱动机制是Node.js通过内部单线程高效率地维护事件循环队列来实现的,没有多线程的资源占用和上下文切换,这意味着面对大规模的http请求,Node.js凭借事件驱动搞定一切,
    习惯了传统语言的网络服务开发人员可能对多线程并发和协作非常熟悉,但是面对Node.js,我们需要接受和理解它的特点。
二,重要概念
  1,什么是 Event Loop ?(很重要的概念)
    Event Loop 是一个很重要的概念,指的是计算机系统的一种运行机制。
    想要理解Event Loop,就要从程序的运行模式讲起。运行以后的程序叫做进程(Process),一般情况下,一个进程一次只能执行一个任务。
    如果有很多任务需要执行,不外乎三种解决方法。
      (1),排队。因为一个进程一次只能执行一个任务,只好等前面的任务执行完了,再执行后面的任务。
      (2),新建进程。使用fork命令,为每个任务新建一个进程。
      (3),新建线程。因为进程太耗费资源,所以如今的程序往往允许一个进程包含多个线程,由线程去完成任务。
    以JavaScript语言为例,它是一种单线程语言,所有任务都在一个线程上完成,即采用上面的第一种方法。一旦遇到大量任务或者遇到一个耗时的任务,网页就会出现"假死",因为JavaScript停不下来,也就无法响应用户的行为。
    你也许会问,JavaScript为什么是单线程,难道不能实现为多线程吗?
    这跟历史有关系:
      JavaScript语言的一大特点就是单线程,也就是说,同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。
      JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。
      比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准?
      所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。
      为了利用多核CPU的计算能力,HTML5提出Web Worker标准,允许JavaScript脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。      所以,这个新标准并没有改变JavaScript单线程的本质。
      回到EventLoop:
      单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。
      如果排队是因为计算量大,CPU忙不过来,倒也算了,但是很多时候CPU是闲着的,因为IO设备(输入输出设备)很慢(比如Ajax操作从网络读取数据),不得不等着结果出来,再往下执行。
      JavaScript语言的设计者意识到,这时主线程完全可以不管IO设备,挂起处于等待中的任务,先运行排在后面的任务。等到IO设备返回了结果,再回过头,把挂起的任务继续执行下去。
      于是,所有任务可以分成两种,一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,
      才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
      如下图:
        
       只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。这个过程会不断重复。
三,实例讲解
  好了,&废话&不多说了,马上开始我们第一个NodeJS应用:&Hello 大熊&。
  打开你最喜欢的编辑器,创建一个HelloWorld.js文件。
  代码如下:
1 var http = require("http") ;
2 http.createServer(function(request,response){
response.writeHead(200,{
"Content-Type" : "text/plain"
response.write("Hello,大熊 !") ;
response.end() ;
8 }).listen(8888) ;
  我们来运行并且测试这段代码。首先,用Node.js执行你的脚本:
  打开命令行工具CMD,切换到你的工作目录,运行命令&node HelloWorld.js&
  接下来,打开浏览器访问&http://localhost:8888/&,你会看到一个写着 &Hello,大熊 !& 的网页。
  一点小的扩展知识:
  如下图所示,这是NodeJS中的http.js部分源码,createServer是一个对用户很友好的接口,内部实现采用了单例模式,这样做的好处是,把实例的创建和初始化任务进行有效的分离,职责专一,降低耦合度,这是大家平时编程时可以借鉴的思想。
  哈哈哈,是不是很有意思,这只是一次短暂的体验,后面会陆续讲解很多的知识点,大家慢慢体会O(&_&)O哈哈~
四,总体概述
  1,它是一个Javascript运行环境
  2,依赖于Chrome V8引擎进行代码解释
  3,事件驱动
  4, 非阻塞I/O
  5, 轻量、可伸缩,适于实时数据交互应用
  6,单进程,单线程
  最后我想说的话是:这篇的例子不是很多,但是这些概念相当重要,一定要有一个清晰的理解,这样为以后的NodeJS学习会打下牢固的基础的,朋友们加油一起努力。
      & 哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼&&(*^__^*) & & & & & &
阅读(...) 评论()一,开篇分析
首先&Http&这个概念大家应该比较熟悉了,它不是基于特定语言的,是一个通用的应用层协议,不同语言有不同的实现细节,但是万变不离其宗,思想是相同的,
NodeJS作为一个宿主运行环境,以JavaScript为宿主语言,它也有自己实现的一套标准,这篇文章我们就一起来学习一下 &Http模块& 。但是作为前提来说,
希望大家可以先阅读一下官网提供的api,有一个前置了解,这样就方便多了,以下是Http部分的api概览:
http.STATUS_CODES
http.createServer([requestListener])
http.createClient([port], [host])
Class: http.Server
事件 : 'request'
事件: 'connection'
事件: 'close'
Event: 'checkContinue'
事件: 'connect'
Event: 'upgrade'
Event: 'clientError'
server.listen(port, [hostname], [backlog], [callback])
server.listen(path, [callback])
server.listen(handle, [callback])
server.close([callback])
server.maxHeadersCount
server.setTimeout(msecs, callback)
server.timeout
Class: http.ServerResponse
事件: 'close'
response.writeContinue()
response.writeHead(statusCode, [reasonPhrase], [headers])
response.setTimeout(msecs, callback)
response.statusCode
response.setHeader(name, value)
response.headersSent
response.sendDate
response.getHeader(name)
response.removeHeader(name)
response.write(chunk, [encoding])
response.addTrailers(headers)
response.end([data], [encoding])
http.request(options, callback)
http.get(options, callback)
Class: http.Agent
new Agent([options])
agent.maxSockets
agent.maxFreeSockets
agent.sockets
agent.freeSockets
agent.requests
agent.destroy()
agent.getName(options)
http.globalAgent
Class: http.ClientRequest
Event 'response'
Event: 'socket'
事件: 'connect'
Event: 'upgrade'
Event: 'continue'
request.write(chunk, [encoding])
request.end([data], [encoding])
request.abort()
request.setTimeout(timeout, [callback])
request.setNoDelay([noDelay])
request.setSocketKeepAlive([enable], [initialDelay])
http.IncomingMessage
事件: 'close'
message.httpVersion
message.headers
message.rawHeaders
message.trailers
message.rawTrailers
message.setTimeout(msecs, callback)
message.method
message.url
message.statusCode
message.socket
让我们先从一个简单例子开始,创建一个叫server.js的文件,并写入以下代码:
1 var http = require('http') ;
2 var server = http.createServer(function(req,res){
3 res.writeHeader(200,{
'Content-Type' : 'text/charset=utf-8'
// 添加charset=utf-8
6 res.end("Hello,大熊!") ;
8 server.listen(8888) ;
9 console.log("http server running on port 8888 ...") ;
(node server.js)以下是运行结果:
二,细节分析实例
具体看一下这个小例子:
(1行):通过"require"引入NodeJS自带的"http"模块,并且把它赋值给http变量。
(2行):调用http模块提供的函数:"createServer" 。这个函数会返回一个新的web服务器对象。
  参数 "requestListener"&是一个函数,它将会自动加入到 "request"&事件的监听队列。
  当一个request到来时,Event-Loop会将这个Listener回调函数放入执行队列, node中所有的代码都是一个一个从执行队列中拿出来执行的。
  这些执行都是在工作线程上(Event Loop本身可以认为在一个独立的线程中,我们一般不提这个线程,而将node称呼为一个单线程的执行环境),
  所有的回调都是在一个工作线程上运行。
  我们在再来看一下"requestListener"这个回调函数,它提供了两个参数(request,response),
  每次收到一个请求时触发。注意每个连接又可能有多个请求(在keep-alive的连接中)。
  "request"是http.IncomingMessage的一个实例。"response"是http.ServerResponse的一个实例。
  一个http request对象是可读流,而http response对象则是可写流。
  一个"IncomingMessage"对象是由http.Server或http.ClientRequest创建的,
  并作为第一参数分别传递给"request"和"response"事件。
  它也可以被用来访问应答的状态,头文件和数据。
  它实现了 &接口以及以下额外的事件,方法和属性。(具体参考api)。
(3行):&writeHeader&,使用 "response.writeHead()"&&函数发送一个Http状态200和Http头的内容类型(content-type)。
  向请求回复响应头。"statusCode"是一个三位是的HTTP状态码,例如&404&。最后一个参数,"headers",是响应头的内容。
  举个栗子:
1 var body = 'hello world' ;
2 response.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
 注意:Content-Length 是以字节(byte)计算,而不是以字符(character)计算。
  之前的例子原因是字符串 &Hello World !& 只包含了单字节的字符。
  如果body包含了多字节编码的字符,就应当使用Buffer.byteLength()来确定在多字节字符编码情况下字符串的字节数。
  需要进一步说明的是Node不检查Content-Lenth属性和已传输的body长度是否吻合。
 statusCode是一个三位是的HTTP状态码, 例如:"404" 。这里要说的是 "http.STATUS_CODES" ,全部标准"Http"响应状态码的集合和简短描述都在里面。
 如下是源码参考:
1 var STATUS_CODES = exports.STATUS_CODES = {
100 : 'Continue',
101 : 'Switching Protocols',
102 : 'Processing',
// RFC 2518, obsoleted by RFC 4918
200 : 'OK',
201 : 'Created',
202 : 'Accepted',
203 : 'Non-Authoritative Information',
204 : 'No Content',
205 : 'Reset Content',
206 : 'Partial Content',
207 : 'Multi-Status',
// RFC 4918
300 : 'Multiple Choices',
301 : 'Moved Permanently',
302 : 'Moved Temporarily',
303 : 'See Other',
304 : 'Not Modified',
305 : 'Use Proxy',
307 : 'Temporary Redirect',
400 : 'Bad Request',
401 : 'Unauthorized',
402 : 'Payment Required',
403 : 'Forbidden',
404 : 'Not Found',
405 : 'Method Not Allowed',
406 : 'Not Acceptable',
407 : 'Proxy Authentication Required',
408 : 'Request Time-out',
409 : 'Conflict',
410 : 'Gone',
411 : 'Length Required',
412 : 'Precondition Failed',
413 : 'Request Entity Too Large',
414 : 'Request-URI Too Large',
415 : 'Unsupported Media Type',
416 : 'Requested Range Not Satisfiable',
417 : 'Expectation Failed',
418 : 'I\'m a teapot',
// RFC 2324
422 : 'Unprocessable Entity',
// RFC 4918
423 : 'Locked',
// RFC 4918
424 : 'Failed Dependency',
// RFC 4918
425 : 'Unordered Collection',
// RFC 4918
426 : 'Upgrade Required',
// RFC 2817
500 : 'Internal Server Error',
501 : 'Not Implemented',
502 : 'Bad Gateway',
503 : 'Service Unavailable',
504 : 'Gateway Time-out',
505 : 'HTTP Version not supported',
506 : 'Variant Also Negotiates',
// RFC 2295
507 : 'Insufficient Storage',
// RFC 4918
509 : 'Bandwidth Limit Exceeded',
510 : 'Not Extended'
// RFC 2774
节选自,Nodejs源码 &http.js& 143行开始。
其实从客户端应答结果也不难看出:
(6行):&response.end&------当所有的响应报头和报文被发送完成时这个方法将信号发送给服务器。服务器会认为这个消息完成了。
 &每次响应完成之后必须调用该方法。如果指定了参数 &data& ,就相当于先调用 &&response.write(data, encoding) & 之后再调用 &response.end()& 。
(8行):&server.listen(8888)& ------&服务器用指定的句柄接受连接,绑定在特定的端口。
以上就是一个比较详细的分析过程,希望有助于加深理解,代码虽然不多,但是重在理解一些细节机制,以便日后高效的开发NodeJS应用。
三,实例赏心
除了可以使用"request"对象访问请求头数据外,还能把"request"对象当作一个只读数据流来访问请求体数据。
这是一个"POST"请求的例子:
1 http.createServer(function (request, response) {
var body = [];
console.log(request.method) ;
console.log(request.headers) ;
request.on('data', function (chunk) {
body.push(chunk);
request.on('end', function () {
body = Buffer.concat(body) ;
console.log(body.toString()) ;
12 }).listen(8888) ;
下是一个完整的&Http&请求数据内容。
1 POST / HTTP/1.1
2 User-Agent: curl/7.26.0
3 Host: localhost
4 Accept: */*
5 Content-Length: 11
6 Content-Type: application/x-www-form-urlencoded
7 Hello World
四,总结一下
(1),理解 "Http" 概念。
(2),熟练使用&"Http"&相关的api。
(3),注意细节的把控,比如:&POST,GET& 之间的处理细节。
(4),"requestListener"的理解。
(5),强调一个概念:一个http request对象是可读流,而http response对象则是可写流 。
&              &&哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼&&(*^__^*) & & & & & &&
阅读(...) 评论()有人见过 js 仿 触摸滑动屏幕的效果没或者htc&sense2.0的&3d&滑动效果具体效果:鼠标拖拽&&页面根据鼠标移动速度&滑动屏幕有人见过此类js效果吗???/news-230217.htmjquery--ui:http://www.oschina.net/p/jquery-iphone-ui?tp=3一,开篇分析
Hi,大家!大熊君又来了,今天这系列文章主要是说说如何开发基于&JavaScript&的插件式开发,我想很多人对&插件&这个词并不陌生,
有的人可能叫&组件&或&部件&,这不重要,关键是看如何设计,如何做一个全方位的考量,这是本文的重点阐述的概念。我想大家对
&jQuery插件的方式&有一定的了解,我们结合这个话题一起讨论一下,最终给出相关的实现方案,来不断提高自己的谁能力。
  &        
二,进入插件正题
一般来说,jQuery插件的开发分为两种:一种是挂在jQuery命名空间下的全局函数,也可称为静态方法。
另一种是jQuery对象级别的方法,即挂在jQuery原型下的方法,这样通过选择器获取的jQuery对象实例也能共享该方法。
(1),类级别的插件开发
类级别的插件开发最直接的理解就是给"jQuery"类添加类方法,可以理解为添加静态方法。典型的例子就是"$.ajax()"这个函数,将函数定义于jQuery的命名空间中。关于类级别的插件开发可以采用如下几种形式进行扩展:
1.1添加一个全局函数,我们只需如下定义,看代码: 
$.hello = function(){
alert("Hello,大熊君!") ;
1.2添加多个全局函数,可采用如下定义:
1 $.extend({
hello : function(name){
// put your code here
world : function(){
// put your code here
说明:&$.extend(target, [object1], [objectN])&(该方法主要用于合并两个或更多对象的内容(属性)到第一个对象,并返回合并后的第一对象。
如果该方法只有一个参数target,则该参数将扩展jQuery的命名空间,即作为静态方法挂在jQuery全局对象下)。
(2),对象级别的插件开发
 对象级别的插件开发需要如下的两种形式:
 2.1通过&$.fn.extend()&为原型动态挂载相关的属性。
1 (function($){
$.fn.extend({
pluginName : function(opts){
// put your code here
7 })(jQuery) ;
 2.2直接添加动态属性到原型链上。
1 (function($) {
$.fn.pluginName = function(){
// put your code here
5 })(jQuery) ;
  说明一下:二者是等价的,对于一个jQuery插件,一个基本的函数就可以很好地工作,但是对于复杂一点的插件就需要提供各种各样的方法和私有函数。
你可能会使用不同的命名空间去为你的插件提供各种方法,但是添加过多的命名空间反而会使代码变得混乱,健壮性下降。所以最好的解决办法是适当地定义私有函数和方法。
所以我们通过自执行函数与闭包的结合实现模拟的私有插件单元,就像我们上面的实例中一样。
(三),下面给一个简单的例子看看实现的过程:
  (1),&html&片段代码,如下:
1 &div id="bb" style="width:220border:1px solid #"&
&span&&/span&
style="margin-top:10
margin-bottom:30"
  (2),&data.json&定义如下:
    "text" : "你好,大熊君{{bb}} !" ;  }
  (3),"bb.js"代码如下:
1 $(function(){
$("#bb").bigbear() ;
4 (function($){
$.fn.bigbear = function(opts){
opts = $.extend({},$.fn.bigbear.defaults,opts) ;
return this.each(function(){
var elem = $(this) ;
elem.find("span").text(opts["title"]) ;
$.get(opts["url"],function(data){
elem.find("div").text(data["text"]) ;
$.fn.bigbear.defaults = {
title : "这是一个简单的测试" ,
url : "data.json"
19 })(jQuery) ;
  运行效果:
  小结一下:
  (1)&$.fn.bigbear.defaults&提供插件的默认参数选项一个扩展性良好的插件应该是可以让使用者根据需求自定义参数选项,并控制插件的行为,所以提供恢复默认选项是很有必要的。你可以通过jQuery的extend方法来设置这些选项。
  (2),&return this.each(){...}&遍历多个元素并返回jQuery使用Sizzle选择器引擎,Sizzle可以为你的函数提供多元素操作(例如对所有类名相同的元素)。这是jQuery几个优秀的特性之一,在开发插件过程中即使你不准备为你的插件提供多元素支持,但为这做准备仍然是一个很好的方式。另外,jQuery有一个很好的特点就是可以进行方法级联,也可称为链式调用,所以我们不应该破坏这个特性,始终在方法中返回一个元素。
(四),最后总结
  (1),jQuery为开发插件提拱了两个方法,分别是:jQuery.fn.extend(object);&&给jQuery对象添加方法。jQuery.extend(object); &为扩展jQuery类本身.为类添加新的方法。
  (2),把全部代码放在闭包(一个即时执行函数)里此时闭包相当于一个私有作用域,外部无法访问到内部的信息,并且不会存在全局变量的污染情况。官方创建开发规范的解释是:a) 避免全局依赖;b) 避免第三方破坏;c) 兼容jQuery操作符'$'和'jQuery '。
  (3),提供插件的默认参数选项一个扩展性良好的插件应该是可以让使用者根据需求自定义参数选项,并控制插件的行为,所以提供恢复默认选项是很有必要的。你可以通过jQuery的extend方法来设置这些选项
  (4),遍历多个元素并返回jQuery使用Sizzle选择器引擎,Sizzle可以为你的函数提供多元素操作(例如对所有类名相同的元素)。这是jQuery几个优秀的特性之一,在开发插件过程中即使你不准备为你的插件提供多元素支持,但为这做准备仍然是一个很好的实践。另外,jQuery有一个很好的特点就是可以进行方法级联,也可称为链式调用,所以我们不应该破坏这个特性,始终在方法中返回一个元素。
  (5),一次性代码放在主循环以外这一条很重要,但是常常被忽略。简单的讲,如果你有一段代码是一堆默认值,只需要被实例化一次,而不是每次调用你插件功能的时候都需要实例化,你应该把这段代码放在插件方法的外面。
  (6),大家学习完思考一下,如果项目技术选型换了这些插件又是强依赖&jQuery&机制,我们以前写的插件将会不能用(假设不用jQuery的情况),如何做重构那?
明天的文章就会说一下这个问题,并且将会重构插件的关键逻辑,敬请期待。。。
            
                &哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼&&(*^__^*)               & & & &&&&&&
阅读(...) 评论()一,开篇分析
从今天开始,我们来深入具体的模块学习,这篇文章是这个系列文章的第三篇,前两篇主要是以理论为主,相信大家在前两篇的学习中,
对NodeJS也有一个基本的认识,没事!!!趁热打铁,让我们继续将NodeJS进行到底,好了废话不多说,直接进入今天的主题 &Net模块& ,那么&Net&应该如何理解那?
它是做什么用的那?(Net模块可用于创建Socket服务器或Socket客户端。&NodeJS 的数据通信,最基础的两个模块是 Net 和 Http,前者是基于 Tcp 的封装,后者本质还是 Tcp 层,只不过做了比较多的数据封装,我们视为表现层)。
这里参考一下NodeJS &http.js& 中的源码:
从图中不难看出 HttpServer继承了Net类,具有了相关的通信能力,做了比较多的数据封装,我们视为更高级的表现层。
&扩展知识(以下是&inherits&的源码):
1 exports.inherits = function(ctor, superCtor) {
ctor.super_ = superC
ctor.prototype = Object.create(superCtor.prototype, {
constructor: {
value: ctor,
enumerable: false,
writable: true,
configurable: true
功能是实现继承复用。
刚才做了一个简要的概述,里面有一些常用的概念,这里做个简短的概念普及介绍:
  (1),TCP/IP------TPC/IP协议是传输层协议,主要解决数据如何在网络中传输。
  (2),Socket------socket则是对TCP/IP协议的封装和应用(程序层面)。
  (3),Http------HTTP是应用层协议,主要解决如何包装数据。
  (4),网络七层模型------物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。
  总结一下:Socket是对TCP/IP协议的封装,Socket本身并不是协议,而是一个调用接口(API)。
  从而形成了我们知道的一些最基本的函数接口,比如Create、Listen、Connect、Accept、Send、Read和Write等等。
  TCP/IP只是一个协议栈,就像操作系统的运行机制一样,必须要具体实现,同时还要提供对外的操作接口
  实际上,传输层的TCP是基于网络层的IP协议的,而应用层的HTTP协议又是基于传输层的TCP协议的,而Socket本身不算是协议,就像上面所说,它只是提供了一个针对TCP或者UDP编程的接口。
二,体验一把
好了,概念我们也有了,来个例子:
1,建立server.js
1 var net = require('net') ;
2 var server = net.createServer(function(c) { // Connection监听器
console.log("服务器已连接") ;
c.on("end", function() {
console.log("服务器已断开") ;
c.write("Hello,Bigbear !\r\n") ;
c.pipe(c) ;
10 server.listen(8124, function() { // Listening监听器
console.log("服务器已绑定") ;
2,建立client.js
1 var net = require('net') ;
2 var client = net.connect({
port: 8124
4 },function(){ // connect监听器
console.log("客户端已连接") ;
client.write('Hello,Baby !\r\n') ;
8 client.on("data", function(data) {
console.log(data.toString()) ;
client.end() ;
12 client.on("end", function(){
console.log("客户端断开连接") ;
分析一下:
服务端------net.createServer&创建一个 TCP 服务,这个服务绑定(server.listen)在 8124 这个端口上,创建 Server 后我们看到有一个回调函数,
在调用上面函数的时候传入一个参数,这个参数也是函数,并且接受了 socket ,这个由其他方法构造的一个管道(pipe),他的作用就是用来数据交互的。
pipe 是需要 Client 跟 Server 打招呼才能建立的,如果此刻没有客户端访问 Server,这个 socket 就不会存在了。
客户端------net.connect&顾名思义,就是连接到服务端,第一个参数是对象,设置端口(port)为 8124,也就是我们服务器监听的端口,由于没有设置 host 参数,那默认就是 localhost (本地)。
在 Server 中,socket 是管道的一端,而在 client 中,client 本身就是管道的一端,如果是多个客户端连接 Server,Server 会新建多个 socket,每个 socket 对应一个 client。
运行结果:
三,案例引入
(1),下面代码仅仅是服务器向客户端输出一段文本,完成服务端到客户端的单向通讯。
1 // &Sever --& Client 的单向通讯
2 var net = require('net');
4 var chatServer = net.createServer();
6 chatServer.on('connection', function(client) {
client.write('Hi!\n'); // 服务端向客户端输出信息,使用 write() 方法
client.write('Bye!\n');
client.end(); // 服务端结束该次会话
13 chatServer.listen(9000);
Telnet测试一下:telnet&127.0.0.1:9000&
执行 telnet&后,与服务点连接,反馈 Hi! Bye! 的字符,并立刻结束服务端程序终止连接。
如果我们要服务端接到到客户端的信息?
可以监听 server.data 事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息)。
(2),监听 server.data 事件并且不要中止连接(否则会立刻结束无法接受来自客户端的消息)。
1 // 在前者的基础上,实现 Client --& Sever 的通讯,如此一来便是双向通讯
2 var net = require('net');
3 var chatServer = net.createServer(),&& &
4 &&& clientList = [];
6 chatServer.on('connection', function(client) {
7 & // JS 可以为对象自由添加属性。这里我们添加一个 name 的自定义属性,用于表示哪个客户端(客户端的地址+端口为依据)
8 & client.name = client.remoteAddress + ':' + client.remoteP &
9 & client.write('Hi ' + client.name + '!\n'); &
10 & clientList.push(client); &
11 & client.on('data', function(data) {&& &
12 &&&& broadcast(data, client);// 接受来自客户端的信息 &
15 function broadcast(message, client) { &
16 &&& for(var i=0;i&clientList.i+=1) {&& &
17 &&&&& if(client !== clientList[i]) {&&&& &
18 &&&&&&& clientList[i].write(client.name + " says " + message);&& &
19 &&&&& } &
22 chatServer.listen(9000);
上面是不是一个完整功能的代码呢?我们说还有一个问题没有考虑进去:那就是一旦某个客户端退出,却仍保留在 clientList&里面,这明显是一个空指针。
(3),处理clientList
1 chatServer.on('connection', function(client) {
client.name = client.remoteAddress + ':' + client.remotePort
client.write('Hi ' + client.name + '!\n');
clientList.push(client)
client.on('data', function(data) {
broadcast(data, client)
client.on('end', function() {
clientList.splice(clientList.indexOf(client), 1); // 删除数组中的制定元素。
Node&TCP&API&已经为我们提供了 end 事件,即客户端中止与服务端连接的时候发生。
(4),优化broadcast
1 function broadcast(message, client) {
var cleanup = []
for(var i=0;i&clientList.i+=1) {
if(client !== clientList[i]) {
if(clientList[i].writable) { // 先检查 sockets 是否可写
clientList[i].write(client.name + " says " + message)
cleanup.push(clientList[i]) // 如果不可写,收集起来销毁。销毁之前要 Socket.destroy() 用 API 的方法销毁。
clientList[i].destroy()
//Remove dead Nodes out of write loop to avoid trashing loop index
for(i=0;i&cleanup.i+=1) {
clientList.splice(clientList.indexOf(cleanup[i]), 1)
注意的是一旦 &end& 没有被触发,会出现异常,所以才做优化工作。
(5),Net&API&中还提供一个 error 事件,用于捕捉客户端的异常
client.on('error', function(e) {
console.log(e);
四,总结一下
1,理解开篇的相关概念
2,认识Http与Net模块之间的关系
3,结合本文的例子,查阅相关api去实践
4,socket客户端与服务器端之间的通信思想
5,有兴趣可以完善一下那个聊天室的例子
      &&哈哈哈,本篇结束,未完待续,希望和大家多多交流够沟通,共同进步。。。。。。呼呼呼&&(*^__^*) & & & & & &
阅读(...) 评论()}

我要回帖

更多关于 总有人要给我介绍对象 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信