Node.js 网络编程(下)实现TCPUDPWebSocket的创建
Posted YuLong~W
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Node.js 网络编程(下)实现TCPUDPWebSocket的创建相关的知识,希望对你有一定的参考价值。
文章目录
TCP服务器与客户端
TCP基础
TCP协议:传输控制协议,提供面向连接的、可靠的数据传输服务
- 面向连接:数据传输之前,客户端与服务器要建立连接
- 可靠的:数据的传输是有序的、要对数据进行校验
TCP数据分组称为段(Segment)。TCP将来自应用层的数据进行分块并封装成TCP段进行发送
TCP连接的建立采用三次握手方法
Scoket:网络套接字,是进行网络连接的数据结构(服务器的Socket和客户端的Socket)
Socket之间的连接过程包括以下3个步骤:
- 服务器监听。服务器端Socket处于等待连接的状态,实时监控网络状态
- 客户端请求。客户端Socket提出连接请求,要连接的目标是服务器端的Socket
- 连接确认
net模块
net模块:实现TCP的连接和服务,封装了大多数的底层的类和服务,方便用户实现TCP协议
导入该模块:
const net = require('net');
1、net.Server类:
可直接用于创建net.Server对象:
const server = new net.Server([options][, connectionlistener])
实现的事件:
事件 | 描述 |
---|---|
close | 当服务器关闭时被触发。如果有连接存在,则直到所有连接结束才会触发这个事件 |
connection | 当一个新的连接建立时被触发,Socket是一个net.Socket的实例对象 |
error | 发生错误时被触发 |
listening | 当服务被绑定后调用server.listen()方法 |
提供的方法:
- server.address() 方法用于返回绑定的ip地址、地址族和服务端口
- server.close() 方法使服务器停止接受建立新的连接并保持现有的连接
- server.listen() 方法用来启动一个服务器来监听连接
net.createServer()方法:
- 语法格式:
net.createServer([options][, connectionlistener])
- 返回一个net.Server类的实例(对象)
- 该方法可以创建一个TCP服务器,是创建net.Server对象的快捷方式
2、net.Socket类:
可以直接创建net.Socket对象:
const client = net.Socket([options])
实现的事件:
事件 | 描述 |
---|---|
close | 当Socket完全关闭时发出该事件 |
connect | 当一个Socket连接成功建立时触发该事件 |
data | 当接收到数据时触发该事件 |
drain | 当写入缓冲区变为空时触发该事件 |
end | 当Socket的另一端发送一个FIN包时触发该事件,从而结束Socket的可读端 |
error | 当错误发生时触发该事件,close事件也会紧接着该事件被触发 |
ready | 当Socket准备使用时触发该事件,connect事件发生后立即触发该事件 |
timeout | 当Socket超时时触发该事件 |
提供的方法:
- socket.connect() 方法用于在指定的Socket上启动一个连接
- socket.write() 方法用于在Socket上发送数据
net.createConnection()方法:
-
语法格式:
net.createConnection(options[, connectListener])
net.createConnection(port[, host][, connectListener])
-
返回启动连接的net.Socket对象
-
当连接建立之后,在返回的Socket上将触发一个connect事件
创建TCP服务器和客户端
创建TCP服务器:
//导入net模块
const net=require('net');
//创建TCP服务器
const server=net.createServer((client)=>{ //client表示客户端
var clientNo=0;//为每个连接到服务端的客户端编号
console.log(clientNo+'号客户端连接');
//绑定 end 事件 客户端断开连接时触发
client.on('end',function () {
console.log(clientNo+'号客户端端口连接');
});
client.write(clientNo+'号客户端,你好');
client.pipe(client); //通过管道操作
//绑定 data 事件 接收客户端的数据时触发
client.on('data',(data=>{
console.log(clientNo+'号客户端发送的数据是:'+data.toString());
}));
});
//绑定 err 事件 连接发生错误时触发
server.on('error',(err=> {
throw err;
}));
//启动监听:指定监听的端口号
server.listen(8234,()=>{
console.log('TCP服务器已经启动');
});
创建TCP客户端:
const net=require('net');
//创建TCP客户端
var client=net.Socket();
//连接服务器 调用 connect方法
client.connect(8234,'127.0.0.1',()=>{
console.log('已经连接到服务器');
client.write('我是TCP客户端');//向服务器发送数据
});
//接收服务器端数据 绑定 data 事件
client.on('data',(data)=>{
console.log('接收的服务器端数据:'+data.toString());
});
//绑定 end 事件
client.on('end',()=>{
console.log('结束数据');
});
UDP服务器与客户端
UDP基础
UDP协议:用户数据报协议,提供的是不可靠的、面向无连接的传输服务(只有数据的发送方和接收方)
- 面向无连接:在传输数据之前没有明确的连接链路(即不是所有的数据都是通过一条链路传输)
- 不可靠的:数据传输不是通过一条链路完成的,因此接收方法接受的数据不一定是按发送的顺序接受,可能造成数据包的丢失
UDP传输给IP的数据单元称作UDP数据报(Datagram)
UDP使用 端口号 为不同的应用保留其各自的数据传输通道。UDP使用Socket,只不过是无连接的数据报Socket
dgram模块
dgram模块: 用于实现UDP通信
导入该模块:
const dgram = require('dgram');
1、dgram.Socket类:
-
dgram.Socket类提供实现UDP应用的基本框架
-
dgram.Socket对象是一个封装了数据报功能的事件触发器
-
dgram.Socket实例由dgram.createSocket() 方法创建
实现的事件:
事件 | 描述 |
---|---|
close | 使用close()方法关闭一个Socket之后触发该事件 |
error | 发生任何错误都会触发该事件 |
listening | 当一个Socket开始监听数据报信息时触发该事件 |
message | 当有新的数据报被Socket接收时触发该事件。 |
提供的方法:
- socket.bind() 方法用于设置Socket在指定的端口和地址上监听数据报信息
- socket.send() 方法用于在Socket上发送一个数据报
dgram.createSocket()方法:
- 语法格式:
dgram.createSocket(options[, callback])
dgram.createSocket(type[, callback])
(创建一个特定类型的dgram.Socket对象)
- 该方法用于创建dgram.Socket对象
- 一旦创建了Socket,调用 socket.bind() 方法会指示Socket开始监听数据报消息
创建UDP服务器和客户端
创建UDP服务器:
//导入dgram模块
const dgram=require('dgram');
//创建dgram.Socket对象(服务器端-----数据的接收端)
const server =dgram.createSocket('udp4');
//绑定 error 事件
server.on('error',(err => {
console.log(`服务器异常:${err.stack}`);
}))
//绑定 message 事件 参数msg 客户端发送的数据 参数rinfo 封装了客户端的信息(包括地址、端口号等)
server.on('message',((msg,rinfo)=>{
var str_msg=msg.toString();
console.log(`服务器接收来自:${rinfo.address}:${rinfo.port}的${str_msg}`);
console.log(rinfo);
//向客户端发送事件
server.send('我问你爱不归期',rinfo.port,rinfo.address);
}))
//注册监听
server.on('listening',()=>{
//获取服务器地址
var server_address=server.address();
console.log(`服务器监听:${server_address.address}:${server_address.port}`);
})
//绑定端口
server.bind(41234);
创建UDP客户端:
const dgram=require('dgram');
const client_msg=Buffer.from('你好,我是UDP客户端');
//创建客户端的Socket
const client=dgram.createSocket('udp4');
//绑定事件
client.on('close',()=>{
console.log('Socket已关闭');
})
client.on('error',(err =>{
console.log(err);
}))
client.on('message',((msg,rinfo)=>{
if (msg=='exit'){
client.close();
}
console.log(`接收到来自服务器:${rinfo.address}:${rinfo.port}的信息:${msg.toString()}`);
}))
//向服务器发送数据
client.send(client_msg,41234,'localhost',(error => {
if (error){
client.close();
}
}))
WebSocket服务器与客户端
HTTP存在的问题:
- 每次客户端和服务器端的交互都是一次HTTP的请求和应答的过程,增加了每次传输的数据量,浪费带宽资源。
- 不是真正的实时技术,只是模拟实时的效果,轮询会造成同步延迟。
- 编程比较复杂,尤其是要模拟比较真实的实时效果时。
WebSocket协议突破HTTP的局限性,节省服务器资源和带宽,解决两端的实时数据传输问题
WebSocket实现机制
- 由客户端发起握手,建立连接阶段必须依赖HTTP进行一次握手。两端之间的WebSocket连接建立的同时服务器完成了协议升级,由HTTP升级为WebSocket。连接会一直保持,直到客户端或者服务器任何一方主动关闭。
- 进入数据交换阶段,客户端与服务端可以互相主动发送消息。此阶段数据直接通过TCP通道传输,不再依赖HTTP。WebSocket的数据传输是以 帧(Frame) 的形式传输的。
- 关闭连接,可以由任意一端发起关闭连接的命令。
WebSocket通信过程:
WebSocket协议的应用场合:
- 实时通信:聊天应用
- 实时展示和分析:典型的有实时计数器、图表、日志客户端等
- 文档协同:允许多个用户同时编辑一个文档,且用户能够看到每个用户做出的修改
1、WebSocket服务器:
WebSocket库:ws、WebSocket-Node、faye-websocket-node和socket.io
创建WebSocket服务器对象语法格式:new WebSocket.Server(options[, callback])
WebSocket服务器内置事件:
事件 | 描述 |
---|---|
close | 服务器关闭时被触发。 |
connection | 成功握手连接时触发。 |
error | 发生错误时被触发,可注入一个Error对象。 |
headers | 握手前被触发,允许在发送HTTP头之前检查和修改标题。 |
listening | 绑定端口时被触发。 |
2、WebSocket客户端:
创建WebSocket客户端对象语法格式:
new WebSocket(address[, protocols][, options])
WebSocket客户端内置事件:
事件 | 描述 |
---|---|
close | 连接关闭时被触发,有两个参数code(状态码)和reason(原因)。 |
error | 发生错误时被触发,有一个参数error(错误)。 |
message | 接收到服务器消息时被触发,有一个参数data,表示接收到的数据,类型可以是字符串、Buffer、ArrayBuffer。 |
open | 连接建立时被触发。 |
WebSocket构建实时聊天室
创建WebSocket服务器:
//1、安装ws模块 npm install ws
//2、导入ws模块
const WebSocket=require('ws');
//3、创建WebSocket服务器
const server=new WebSocket.Server({port:8080});
//4、绑定open事件
server.on('open',()=>{
console.log('建立连接');
})
//5、绑定close事件
server.on('close',()=>{
console.log('关闭连接')
})
//6、绑定connection事件 ws参数表示客户端 req表示客户端的请求信息
server.on('connection',(ws,req)=>{
//6.1获取客户端的ip port
const ip=req.connection.remoteAddress;
const port=req.connection.remotePort;
const clientName=ip+port;
console.log('%s is connect',clientName);
//6.2向客户端发送消息
ws.send('欢迎'+clientName);
ws.on('message',(msg)=>{
console.log('消息:%s 来自于 %s',msg,clientName);
//6.3把消息广播所有客户端:clients表示所有客户端
server.clients.forEach(function (client) {
//若某个客户端是打开的,就把消息广播给该客户
if (client.readyState===WebSocket.OPEN){
client.send(clientName+'---------'+msg);
}
})
})
})
创建WebSocket客户端:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>聊天室</title>
</head>
<body>
<script type="text/javascript">
var scoket;
//若浏览器不支持WebSocket
if (!window.WebSocket){
window.WebSocket=window.MozWebSocket;
}
if (window.WebSocket){
//创建客户端的WebSocket对象
socket=new WebSocket('ws://localhost:8080/ws')
//给socket绑定message事件
socket.onmessage=function (event){
//获取textarea标签
let ta=document.getElementById('responseText');
ta.value=ta.value+'\\n'+event.data;
};
//给socket绑定open事件 与服务器建立连接
socket.onopen=function (event){
let ta=document.getElementById('responseText');
ta.value='连接开启';
};
}else{
alert('您的浏览器不支持WebSocket协议');
}
//定义发送消息的函数
function send(message){
if (!window.WebSocket){
return;
}
if (socket.readyState===WebSocket.OPEN){
//向服务器发送消息
socket.send(message);
//清空消息输入框
document.getElementById('msg').value='';
}else{
alert('连接未开启!');
}
}
</script>
<h2>WebSocket聊天室</h2>
<!-- 关闭表单的提交功能-->
<form onsubmit="return false">
<!-- 来显示聊天室的聊天记录-->
<textarea id="responseText" style="height:300px;width: 500px"></textarea>
<br><br>
<input type="text" id="msg" name="message" placeholder="请输入消息"style="width: 300px"/>
<input type="button" value="发送消息" onclick="send(this.form.message.value)"/>
<input type="button" value="清空聊天记录" onclick="javascript:document.getElementById('responseText').value=''">
</form>
</body>
</html>
服务器页面:
客户端页面:
以上是关于Node.js 网络编程(下)实现TCPUDPWebSocket的创建的主要内容,如果未能解决你的问题,请参考以下文章
node.js 回调函数事件循环EventEmitter ar