Node.js API实例讲解——Socket 对象
Socket 对象
net模块有两个类,一个是Socket和Server,下面先讲解Socket。
net.Socket实现了stream.Duplex双工接口,具有了读写的能力。
创建Socket实例
第一种方法 new net.Socket()
var net = require("net"); var socket = new net.Socket();
创建之后也不能做什么,因为没有连接到服务器端,所以需要socket.connect方法建立个连接。
var net = require("net"); var socket = new net.Socket(); socket.connect(8124,function(){ console.log(socket.address()) })
socket.connect(port, [host], [connectListener]) 方法是连接服务器的方法,port表示连接到服务器的端口号;host[可选]参数是服务器地址,默认是localhost;connectListener[可选]参数是个'connect'事件监听器,当连接建立后会触发'connect'事件,但当连接建立失败时,会触发‘error’事件。
第二种方法 net.connect / net.createConnection
net.connect(port, [host], [connectListener])#
net.createConnection(port, [host], [connectListener])
这两个方法一模一样,名字不同而已,前面我们已经看过一个net.connect例子了,和第一个方法参数相同,不过多讲解。
第三种方法 被动创建
其实就是服务器端有一个客户端连进来时,会在服务器端创建一个对应的socket(口)。
net.createServer([connectionListener])方法在例子中见过,下面详细讲解。
connectionListener(socket)是“connection”事件监听器,当有客户端连接进来时,会触发“connection”事件,而这个监听器的socket参数就是被动创建的,是对应连接进来的客户端,当然这是可选参数。
connectionListener是可选参数,如果省略了又如何得到socket呢?答案很简单,看下面代码:
var server = net.createServer(); server.on("connection",function(socket){ // 这个的作用和 [connectionListener]的作用一样。 })
在此一笔带过,在下一节介绍net.Server类时会详细讲解。以上是建立Socket对象的三种方式。
Socket对象的属性
socket.remoteAddress 属性是远程socket的地址。
socket.remotePort 远程socket的端口号。
socket.localAddress 本地socket地址。
socket.localPort 本地socket端口号。
socket.bytesRead 接收到的字节数。
这里的字节量是累积的。
socket.bytesWritten 发送出去的字节数。
这里的字节量是累积的。
虽然这些属性很简单易懂,我们还是为它做个程序。
var net = require('net'); var server = net.createServer(); server.on("connection",function(socket) { console.log("远程socket端口:" + socket.remotePort); console.log("远程socket地址:" + socket.remoteAddress); console.log("本地socket端口:" + socket.localPort); console.log("本地socket地址:" + socket.localAddress); socket.on("data",function(data){ console.log(data.toString()); console.log("接受到字节量:" + socket.bytesRead); socket.write("send byte ... ") console.log("发送的字节量:"+ socket.bytesWritten); }) }) server.listen(8124, function() { console.log('服务器已启动!'); });
socket.setEncoding
参看“流”一章,有详细说明。
socket.write(data, [encoding], [callback])
data参数,要发送出去的数据,data可以是字符串类型或Buffer类型。
encoding[可选]参数,编码方式,默认utf8,当data是字符串类型时有效。
callback[可选]参数,写入成功后被调用。
socket.end([data], [encoding]);
如果有个data参数,那么相当于:
socket.write(data,[encoding],function(){ socket.end(); })
socket.end()就是发出FIN,至于FIN信号,可以理解为告诉另一端socket结束了,然后自己也会结束生命周期,而另一端会触发"end"事件。
socket.destory()
这个方法也是结束生命周期,不过是残酷的被kill了,服务器端不会触发‘end’事件,因为没有发出FIN信号就自杀了,所以另一端会触发"error",本来正常上班,连请假都没有就自杀了,真是可悲。
socket.pause()
这个方法是暂停接受读取数据的动作,也就暂时停止触发socket.on("data"...)事件了。
socket.resume()
恢复读取动作。
【暂停】
这个不是知识点,而是前面说了几个知识点,那又有什么用呢,还是纸上谈兵,应该遵循一个原则,看一些理论,就要动手实践一番。
下面是一个程序,先开发个服务器端和客户端,服务器端接受一个客户的信息,当信息量达到一定bytes数量时就会kill杀了,呵呵。这个game很不错,一起动手开发吧。
服务器代码:
var net = require('net'); var server = net.createServer(); server.on("connection",function(socket) { socket.on("data",function(data){ // 当接受的数据大于1M时,会杀死socket。 if(socket.bytesRead > 1000*1000){ socket.pause(); socket.write("数据量太大,3秒内自动关闭连接!"); setTimeout(function(){ socket.destroy(); },3000); } }) }) server.listen(8124, function() { console.log('服务器已启动!'); });
客户端代码:
var net = require('net'); var fs = require("fs"); // 这个文件很大 var filedata = fs.readFileSync(__dirname+"/1.pdf"); var socket = net.connect(8124,"localhost", function() { socket.write(filedata); } ); socket.on('data', function(data) { // 服务器发来的信息 console.log(data.toString()); });
当1.pdf文件大于1M时,客户端会接收到一个警告“数据量太大,3秒内自动关闭连接!”,三秒后真的被踢出来了,郁闷!呵呵。
fuck通过这个程序,可以加深一下编程功力,下面继续纸上谈兵吧。
socket.setTimeout(timeout, [callback]);
这个方法可以设定空闲超时,timeout是毫秒为单位的,如果设置timeout = 0,那么将撤销先前设置的超时,callback是添加个超时监听器,当有'timeout'事件时会被调用,这是可选的,可以使用 socket.on("timeout",callback)方式进行监听。
不要误会,设定这个空闲超时只能产生'timeout'事件,但是不会有类似切断连接行为。
ok,开发个程序,但客户端空闲10秒钟就会给服务器强行断开。代码如下:
服务器代码:
var net = require('net'); var server = net.createServer(); server.on("connection",function(socket) { console.log("警告:10秒空闲就会被踢出!") socket.setTimeout(10*1000, function(){ console.log("踢出!!"); socket.destroy(); }) }) server.listen(8124, function() { console.log('服务器已启动!'); });
客户端代码:
var net = require("net"); var socket = net.connect(8124); socket.on("data",function(data){ console.log(data.toString()); })
socket.address()
返回一个对象,类似 { address: '127.0.0.1', family: 'IPv4', port: 53068 }
socket对象的事件
socket对象会产生一些事件。
data事件
当接收到数据时会产生这个事件,事件监听器会接收到数据。
socket.on("data",function(data){ // data是一个Buffer对象。 })
end事件
另一端socket调用了end() 方法时,会产生这个事件。
timeout事件
前面已详细说明,就是当socket空闲超时的时候,产生的事件。
drain事件
当调用socket.write方法时,会发送数据,内部有个缓冲区,每次清空缓冲区后都会产生drain事件。
error事件
但有错误产生时,会产生这个事件,一旦产生这个事件,内部也会产生“close”事件。book
socket.on("error",function(err){ // ...... })
close事件
socket.on("error",function(had_error){ })
had_error是个布尔值,如果是true就表示传输错误造成的关闭。
Server对象是等待有连接进入的管家,当客户端把一个管线丢给服务器,服务器接到后就建立了连接,管线两端都有口,也就是socket,管线是中空的,所以服务器和客户端可以相互发送数据和接收数据。
下面详细介绍Server对象的各个细节。
net.createServer([connectionListener])
创建服务器的方法,connectionListener[可选]是Server对象产生‘connection’事件的监听器。这里可以指定,也可以通过 server.on("connection",connectionListener)指定。
var server = net.createServer(); server.on("connection",function(socket) { })
server.listen(port, [host], [backlog], [callback])
即使调用net.createServer 建立了Server对象,但还需要调用 server.listen 启动服务器的监听方法。
port 参数,是打开一个服务器端的监听端口,如果是0,表示由系统分配一个随机端口。
host[可选]参数,允许连入的客户端主机,可以是ip或域名。
backlog[可选]参数,表示同时访问的最大数,默认511。
callback[可选]参数,表示server对象产生“listening”事件的监听器,“listening”事件的产生表示server已经准备妥当,要接受客户端请求了。
server.close([callback])
god这个方法可以保留现有的连接,拒绝新的连接建立。
callback[可选],是监听服务器的“close”事件的监听器,调用server.close不能产生close事件。
close事件的产生有几种情况,第一种情况是当产生error事件时也会产生close事件,第二种情况是调用过server.close方法后,已有的连接都断开连接后,会产生close事件。
server.address()
这个方法很简单,和socket.address()一样。
server.getConnections(callback)
这是异步方法,得到当前连接数,callback(err,count)回调函数,count是当前连接数量。
server对象产生的事件
listening事件
当服务器准备好接受客户端请求时,产生此事件。
connection事件
有新连接进入时,产生此事件。
close事件
god服务器关闭时,会产生此事件。
error事件
当发生错误时产生error事件,同时也会产生close事件。
检查IP有效性
net.isIP(input)
检查input字符串是否是IP,return 0 表示无效,return 4 表示IPv4,return 6表示IPv6。
net.ipIPv4(input)
检查input是否是IPv4 ,return true/false。
net.ipIPv6(input)
检查input是否是IPv6 ,return true/false。
var net = require("net"); console.log(net.isIP("12.444.22.2")); // 0 console.log(net.isIP("112.11.22.122")); // 4 console.log(net.isIP("fe80::dc15:8005:801c:82bb")); // 6 console.log(net.isIPv4("22.212.12.122")); // true console.log(net.isIPv6("22.212.12.122")); // false console.log(net.isIPv6("fe80::dc15:8005:801c:82bb")); // true
【小结】
Socket就是一个管道两端的口,一个管道当然要有两个socket,无论关闭任何一端的socket,对应的也就kill了。
相关文章
- Visual Studio Online 更新!更好支持Docker、Python、Go、C++
- 利用 html2canvas 生成文章缩略图
- 纪录片《穹顶之下》全集103分钟1080P高清完整视频
- DoraCMS v2.1.5 版本更新
- DoraCMS v2.1.2 Docker 版本(生产环境)
- Nodejs 内容管理系统 DoraCMS 2.1.4 发布
- DoraCMS 插件化探索(一)
- DoraCMS 2.1.4 关于 '指定用户' 功能的优化说明
- DoraCMS 2.1.4 (发布版非源码) 抢先体验
- angularjs filter 详解
- angularJs的html转义过滤器
- ng-switch on、ng-if/ng-show/ng-hide/ng-disabled标签