Node之实现基于TCP与UDP的数据通信
在Node.js中,提供了一个net模块,专用于实现TCP服务器与TCP客户端之间的通信。
创建TCP服务器
在Node.js中,可以很方便地创建一个TCP服务器,只需调用net模块中的createServer方法
var server=net.createServer([options],[connectionListener])
options:
- allowHalfOpen:当该属性值被指定为false时,当TCP服务器接收到客户端发送的一个FIN包时将会回发一个FIN包,当该属性值被设定为true时,当TCP服务器接收到客户端发送的一个FIN包时不FIN包,这使得TCP服务器可以继续向客户端发送数据,但是不会继续接收客户端发送的数据。
- connectionListener:用于指定当客户端与服务器端建立连接时所要调用的回调函数。在该回调函数中使用一个参数,参数值为该TCP服务器监听的socket端口对象。
当客户端与服务器端建立连接时,触发connection事件,我们也可以不在createServer方法中使用connectionListener参数,而是通过对connection事件进行监听,并且指定该事件的回调函数的方法来指定当客户端与服务器端建立连接时需要执行的处理
server.on('connection',function(socket){
//回调函数代码略
});
监听
在创建了TCP服务器之后,可以使用listen方法通知服务器开始监听客户端连接。该方法具有如下所示的三种指定方法。
server.listen(port,[host],[backlog],[callback])
- port:用于指定需要监听的端口号,参数值为0时将为TCP服务器分配一个随机端口号,TCP服务器将监听来自于这个随机端口号的客户端连接。
- host:用于指定需要监听的IP地址或主机名,如果省略该参数,服务器将监听来自于任何IPv4地址的客户端连接。
- backlog:参数值为一个整数值,用于指定位于等待队列中的客户端连接的最大数量,一旦超越这个长度,TCP服务器将开始拒绝来自于新的客户端的连接请求,该参数的默认参数值为511。
当对TCP服务器指定了需要监听的地址及端口后,服务器端将立即开始监听来自于该地址及端口的客户端连接,这时触发该服务器的listening事件,可使用listen方法的callback参数来指定listening事件触发时调用的回调函数,该回调函数中不使用任何参数。
方法二:指定方法如下所示(代码中的server代表一个使用unix端口的服务器)。
server.listen(path,[callback])
这种形式的listen方法用于通知一个使用unix端口的服务器开始监听来自于指定路径的客户端连接。
方法三:指定方法如下所示(代码中的server代表一个TCP服务器)。
server.listen(handle, [callback]
在对TCP服务器指定需要监听的地址及端口时,如果该地址及端口已被占用,将产生一个错误代码为“EADDRINUSE”的错误(表示用于监听的地址及端口已被占用),同时将触发TCP服务器的error事件,可以通过对error事件设置回调函数的方法来指定该错误产生时需要执行的处理。该回调函数的指定方法如下所示
server.on('error', function (e) {
if (e.code == 'EADDRINUSE') {//当地址及端口被占用时错误代码为'EADDRINUSE'
//可以在此处指定当地址及端口被占用时所需执行的处理
}
});
在创建了TCP服务器之后,可以使用TCP服务器的address方法来查看该服务器所监听的地址信息,因此开发者应该在服务器的listening事件被触发后才使用该方法。
var address=server.address()
该方法返回一个对象,其中具有如下所示的属性。
- port:属性值为TCP服务器监听的socket端口号,例如8431。
- address:属性值为TCP服务器监听的地址,例如127.0.0.1。
- family:属性值为一个标识了TCP服务器所监听的地址是IPv4地址还是IPv6地址的字符串,例如“IPv4”。
getConnections():查看当前与TCP服务器建立连接的客户端连接数量
server.getConnections(function (err,count) {
//回调函数代码略
}
)
close():显式指定服务器拒绝所有新的客户端连接。
server.close([callback])
在使用close方法时,并不会断开所有现存的客户端连接。当这些客户端连接被关闭时,TCP服务器将被自动关闭,同时触发TCP服务器的close事件。我们可以在close方法中使用一个不使用任何参数的回调函数来指定当TCP服务器关闭时所需执行的处理。我们也可以不在close方法中使用任何参数,而是通过对close事件进行监听,并且指定该事件的回调函数的方法来指定TCP服务器被关闭时所需执行的处理
socket端口对象
使用socket端口对象的setEncoding方法
socket.setEncoding('utf8');
socket.on('data',function(data){
console.log(data);
});
使用Buffer对象的toString方法
socket.on('data',function(data){
console.log(data.toString());
});
bytesRead: 属性值为该socket端口对象接收到的客户端发送数据的字节数
end:监听客户端被关闭
完整示例:
var net = require('net');
var server = net.createServer();
server.on('connection', function(socket) {
socket.setEncoding('utf8');
socket.on('data',function(data){
console.log(data);
console.log('已接收到%d字节数据。',socket.bytesRead);
});
socket.on('end',function(){
console.log('客户端连接被关闭。');
});
});
server.listen(8431,'localhost');
pipe将客户端发送的流数据书写到文件等其他目标对象中
可以利用socket对象的pipe方法将客户端发送的流数据书写到文件等其他目标对象中
socket.pipe(destination,[options]);
- destination:为一个可用于写入流数据的对象
- options:为一个对象,可以在该对象中使用一个布尔类型的end属性,如果该属性值为true,则当数据被全部读取完毕时立即结束写操作;如果该属性值为false,则并不结束写操作,目标对象中可以被继续写入新的数据,该属性的默认属性值为true
完整示例:
var net = require('net');
var file = require('fs').createWriteStream('./message.txt');
var server = net.createServer();
server.on('connection', function(socket) {
socket.pipe(file);
});
server.listen(8431,'localhost');
unpipe:取消目标对象的写入操作
socket.unpipe([destination]);
pause:暂停data事件的触发
在Node.js中,可以使用socket端口对象的pause方法暂停data事件的触发,这时服务器端将把每一个客户端发送的数据暂存在一个单独的缓存区中。
socket.pause();
恢复data事件的触发
socket.resume();
完整示例:
var net = require('net');
var file = require('fs').createWriteStream('./message.txt');
var server = net.createServer();
server.on('connection', function(socket) {
socket.pipe(file,{end:false});
setTimeout(function() {
file.end('再见。');
socket.unpipe(file);
}, 5000);
});
server.listen(8431,'localhost');
设置超时时间
在Node.js中,未对客户端连接指定默认超时时间,可以使用socket端口对象的setTimeout方法指定与该端口相连接的客户端连接的超时时间(代码中的socket代表一个socket端口对象)。
socket.setTimeout(timeout,[callback])
connection
建立连接以后
创建TCP客户端
在Node.js中,创建TCP客户端是一件非常简单的事情,只需创建一个用于连接TCP服务器的socket端口对象即可,方法如下所示(代码中的socket代表一个socket端口对象)。
var net=new net.Socket([options])
options:
- fd:用于指定一个现存的socket的文件描述符,TCP客户端将使用这个现存的socket端口与服务器端相连接。
- type:用于指定客户端所使用协议,可指定值为“tcp4”、“tcp6”或者“unix”。
- allowHalfOpen:该属性值被指定为false时,当TCP服务器接收到客户端发送的一个FIN包时将会回发一个FIN包,当该属性值被设定为true时,当TCP服务器接收到客户端发送的一个FIN包时不回发FIN包,这使得TCP服务器可以继续向客户端发送数据,但是不会继续接收客户端发送的数据。
使用connect连接
socket.connect(port,[host],[connectListener])
与unix端口的服务器连接
socket.connect(path,[connectListener])
写入数据
socket.write(data,[encoding],[callback])
- data:为一个Buffer对象或一个字符串,用于指定需要写入的数据,当参数值为Buffer对象时表示写入Buffer对象中的数据,参数值为字符串时表示写入该字符串。
- encoding:字符编码
- callback:指定当数据被写入完毕时所要调用的回调函数,在该回调函数中不使用任何参数。
创建TCP客户端:
var net = require('net');
var client = new net.Socket();
client.setEncoding('utf8');
client.connect(8431,'localhost',function(){
console.log('已连接到服务器端。');
client.write('你好。');
});
client.on('data',function(data){
console.log('已接收服务器端发送的数据:'+data);
});
创建TCP服务器:
var net = require('net');
var server = net.createServer();
server.on('connection', function(socket) {
console.log('客户端与服务器端连接已建立。');
socket.setEncoding('utf8');
socket.on('data',function(data){
console.log('已接收客户端发送的数据:'+data);
socket.write('确认数据:'+data);
});
});
server.listen(8431,'localhost');
捕捉错误
socket.on('error',function(err){
//回调函数代码略
});
销毁tcp
socket.destroy()
关闭连接
socket.end([data],[encoding])
当客户端连接被全部关闭时退出应用程序
server.unref()
ref方法继续阻止应用程序的退出
server.ref()
使用TCP服务器对象的close方法拒绝新的客户端连接请求
var net = require('net');
var server = net.createServer();
server.on('connection', function(socket) {
console.log('客户端与服务器端连接已建立。');
socket.setEncoding('utf8');
socket.on('data',function(data){
console.log('已接收客户端发送的数据:'+data);
socket.write('确认数据:'+data);
});
socket.on('error',function(err){
console.log('与客户端通信的过程中发生了一个错误,错误编码为%s。',err.code);
socket.destroy();
});
socket.on('end',function(){
console.log(' 客户端连接被关闭。');
server.unref();
});
socket.on('close',function(had_error){
if(had_error){
console.log('由于一个错误导致socket端口被关闭。');
server.unref();
}
else
console.log('socket端口被正常关闭。');
});
server.getConnections(function(err,count){
if(count==2)
server.close();
});
});
server.listen(8431,'localhost');
server.on('close',function(){
console.log('TCP服务器被关闭。');
});
setKeepAlive()
在TCP客户端与服务器端建立连接后,当一方主机突然出现断电、重启、系统崩溃等意外情况时,将来不及向另一方发送用于关闭连接的FIN包,这样另一方将永远处于连接状态。在Node.js中,可以通过使用用于建立客户端连接或服务器端连接的socket端口对象的setKeepAlive方法来解决这一问题
socket.setKeepAlive([enable],[initialDelay])
- enable:true/false
- initialDelay:用于指定每隔多久发送一次探测包,单位为毫秒,如果将该参数值设置为0,则保持操作系统中的默认设置的Keep-alive探测包的发送间隔时间,或者保持程序中当前已设置的Keep-alive探测包的发送间隔时间,该参数值默认为0。
在socket端口对象的setKeepAlive方法中,使用两个可选参数。第一个参数为一个布尔类型的参数值,当参数值为true时,启用Keep-alive机制。启用Keepalive机制后,使用了setKeepAlive方法的这一方会不断地向对方发送一个探测包,如果发送探测包后对方没有发回响应的话,则认为对方已关闭连接,执行对方关闭连接时应该执行的处理,如果该参数值为false,则不启用Keep-alive机制,该属性值默认为false,即不采用Keep-alive机制。setKeepAlive方法中的第二个参数值为一个整数值,用于指定每隔多久发送一次探测包,单位为毫秒,如果将该参数值设置为0,则保持操作系统中的默认设置的Keep-alive探测包的发送间隔时间,或者保持程序中当前已设置的Keep-alive探测包的发送间隔时间,该参数值默认为0。
net模块中的类方法
isIP方法
isIP方法用于判断一个字符串值是否为一个IP地址,该方法使用一个字符串参数,如果字符串值不为IP地址,方法返回0;如果字符串值为IPv4地址,方法返回4;如果字符串值为IPv6地址,方法返回6。
net.isIP(input)
isIPv4方法
isIPv4方法用于判断一个字符串值是否为一个IPv4地址,该方法使用一个字符串参数,如果字符串值为一个有效的IPv4地址,则方法返回true,否则返回false。
net.isIPv4(input)
isIPv6方法
isIPv6该方法用于判断一个字符串值是否为一个IPv6地址,该方法使用一个字符串参数,如果字符串值为一个有效的IPv6地址,则方法返回true,否则返回false。
net.isIPv6(input)
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。