【Node】Node实现网络编程

文章目录

TCP

TCP基础

TCP协议:传输控制协议,提供面向连接的、可靠的数据传输服务

  • 面向连接:数据传输之前,客户端与服务器端要建立连接
  • 可靠的:数据传输是有序的、要对数据进行校验

Scoket:网络套接字,是进行网络连接的数据结构(服务器的Socket和客户端的Socket)

  • 服务器的Socket:实现对指定端口号的监听,若有客户端向监听的端口发出连接请求,Socket就会监听到
  • 客户端的Socket:向服务器端发送请求

TCP数据分组称为段(Segment)。TCP将来自应用层的数据进行分块并封装成TCP段进行发送。
TCP连接的建立采用三次握手方法。

Socket之间的连接过程包括以下3个步骤。

  • 服务器监听。服务器端Socket处于等待连接的状态,实时监控网络状态。
  • 客户端请求。客户端Socket提出连接请求,要连接的目标是服务器端的Socket。
  • 连接确认

net模块提供的API

Node中的net模块:实现TCP的连接和服务,封装了大多数的类和方法,方便用户使用TCP进行网络连接

导入该模块:
const net = require('net');

net.Server类: 服务器类,用于创建TCP服务器

创建net.Server对象

  • const server = new net.Server([options][, connectionlistener])
  • const server = net.createServer([参数])

返回一个net.Server类的实例(对象)。
该方法可以创建一个TCP服务器,是创建net.Server对象的快捷方式。
用法:
net.createServer([options][, connectionlistener])

net.Server类实现的事件:

  • close:当服务器关闭时被触发。如果有连接存在,则直到所有连接结束才会触发这个事件。
  • connection:当一个新的连接建立时被触发,Socket是一个net.Socket的实例对象。
  • error:发生错误时被触发。
  • listening:当服务被绑定后调用server.listen()方法。

net.Server类提供的方法:

  • server.address()方法用于返回绑定的ip地址、地址族和服务端口。
  • server.close()方法使服务器停止接受建立新的连接并保持现有的连接
  • server.listen()方法用来启动一个服务器来监听连接。

net.Socket: 客户端类,用于创建TCP客户端

创建net.Socket对象:

  • const client = net.Socket([options])

net.Socket类实现的事件:

  • close:当Socket完全关闭时发出该事件。
  • connect:当一个Socket连接成功建立时触发该事件。
  • data:当接收到数据时触发该事件。
  • drain:当写入缓冲区变为空时触发该事件。
  • end:当Socket的另一端发送一个FIN包时触发该事件,从而结束Socket的可读端。
  • error:当错误发生时触发该事件。close事件也会紧接着该事件被触发。
  • ready:当Socket准备使用时触发该事件。connect事件发生后立即触发该事件。
  • timeout:当Socket超时时触发该事件。

net.Socket类提供的方法:

  • socket.connect():用于在指定的Socket上启动一个连接。
  • socket.write():用于在Socket上发送数据。

net.createConnection()方法

  • 返回启动连接的net.Socket对象。
  • 当连接建立之后,在返回的Socket上将触发一个connect事件。
  • 语法格式:
    net.createConnection(options[, connectListener])
    net.createConnection(port[, host][, connectListener])

Node实现TCP

创建服务器端:

// 导入net模块
const net = require('net');

// 创建TCP服务器
const server = net.createServer((client) => {    //'client'表示的客户端
    let 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());
    }))
});

// 绑定'error'事件:当连接发生错误时触发
server.on('error',(err => {
    throw err;
}))

// 启动监听:指定监听的端口号
server.listen(8000,() => {
    console.log('TCP服务器已经启动了!!!');
})

创建客户端:

const net = require('net');

//创建TCP客户端
var  client = net.Socket();

//连接服务器:调用connect方法
client.connect(8000,'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');

dgram.Socket类

  • dgram.Socket类提供实现UDP应用的基本框架。
  • dgram.Socket对象是一个封装了数据报功能的事件触发器。
  • dgram.Socket实例由dgram.createSocket()方法创建。

dgram.Socket类实现的事件:

  • close:使用close()方法关闭一个Socket之后触发该事件。
  • error:发生任何错误都会触发该事件。
  • listening:当一个Socket开始监听数据报信息时触发该事件。
  • message:当有新的数据报被Socket接收时触发该事件。

dgram.Socket类提供的方法:

  • socket.bind()方法用于设置Socket在指定的端口和地址上监听数据报信息。
  • socket.send()方法用于在Socket上发送一个数据报。

dgram.createSocket()方法

  • 该方法用于创建dgram.Socket对象。一旦创建了Socket,调用socket.bind()方法会指示Socket开始监听数据报消息。
  • 基本用法:dgram.createSocket(options[, callback])
  • 创建一个特定类型的dgram.Socket对象:dgram.createSocket(type[, callback])

Node实现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(8089);

客户端:

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',() => {
    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,8089,'localhost',(error => {
    if(error) {
        client.close();
    }
}))

在这里插入图片描述

在这里插入图片描述

HTTP

HTTP基础

HTTP是一种通用的、无状态的、与传输数据无关的应用层协议

客户端与服务器之间的HTTP交互过程:

  1. 客户端和服务器建立TCP连接
  2. 客户端向服务器发送HTTP请求报文
  3. 服务器向客户端返回HTTP响应报文
  4. 关闭HTTP连接。

http模块

导入HTTP模块:
const http = reuqire('http')

http.Server类:

  • http.Server类提供了实现HTTP服务器的基本框架。

http.Server类主要实现的功能

  • 基于TCP连接建立一个网络监听器。
  • 监听自身的request请求事件。

http.createServer()方法:

  • 要启动HTTP服务器,需要使用http.createServer()方法创建一个http.Server对象。
  • 该方法的用法:http.createServer([options][, requestlistener])

http.Server类实现的事件:

  • request:当有请求时会触发该事件,提供两个参数request和response,分别为http.IncomingMessage对象和http.ServerResponse对象,表示请求和响应的信息。
  • connect:客户端请求HTTP的CONNECT方法时触发该事件。
  • connection:当TCP建立连接时触发该事件,提供参数socket通常表示net.Socket对象。
  • close:当服务器关闭时触发该事件。
  • clientError:如果客户端连接触发error事件,则会在此处转发。

http.Server类提供的方法:

  • server.listen() :启动HTTP服务器监听连接。
  • server.close():停止服务器接受新连接。

http.IncomingMessage类——传入的信息

  • http.IncomingMessage对象(该类实例)由http.Server或http.ClientRequest创建。

http.IncomingMessage类实现的事件:

  • aborted:当请求中止时被触发。
  • close:表明底层连接已关闭。

http.IncomingMessag属性:
在这里插入图片描述

http.ServerResponse类——响应

  • 指定要发送到客户端的响应

http.ServerResponse类实现的事件:

  • close:调用response.end()方法,或者能够刷新之前已终止的底层连接。
  • finish:响应发送后触发该事件。

关于响应头的额外方法:

  • response.setHeader(name, value):设置一个特定的响应头。
  • getHeader(name):获取已在响应中设置的某个响应头。
  • removeHeader(name):移除已在响应中设置的某个响应头。
  • response.addTrailers(headers):将HTTP尾部响应头添加到响应中。
  • response.writeHead(statusCode,[reasonPhrase],[headers]):将某个响应头写入请求。

关于响应体的方法:

  • response.write(data,[encoding]):发送响应体。
  • response.writeContinue():向客户端发送HTTP/1.1 100 Continue消息,表示应发送请求体。
  • response.end([data][,encoding][,callback]):结束响应,向服务器表明已发送所有的响应头和响应体。

属性:

  • response.statusCode:刷新响应头时将发送到客户端的状态码。
  • response.statusMessage:刷新响应头时将发送到客户端的状态消息。

http.ClientRequest类

  • http.ClientRequest类提供了实现HTTP客户端的基本框架。
  • 通过http.request()方法创建并返回一个http.ClientRequest对象,作为HTTP客户端,启动、监控和处理来自服务器的响应。

http.request()方法:

  • 构建一个HTTP客户端,需使用http.request()方法创建一个ClientRequest对象。
  • 该方法的两种用法:
    http.request(options[, callback])
    http.request(url[, options][, callback])

实现的事件:

  • abort:当请求被客户端中止时被触发。
  • connect:每次服务器使用CONNECT方法响应请求时都会触发该事件。
  • continue:当服务器发送“100 Continue”HTTP响应时被触发。
  • response:当收到此请求的响应时被触发。此事件仅触发一次。
  • socket:将Socket分配给此请求后被触发。
  • timeout:当底层Socket因处于不活动状态而超时时被触发。

用于请求头的方法:

  • request.setHeader(name, value):设置一个特定的请求头。
  • request.getHeader(name):读取请求中的一个请求头。
  • request.flushHeaders():刷新请求头。

用于请求体的方法:

  • request.write(chunk[, encoding][, callback]):发送一个请求体的数据块。
  • request.end([data[, encoding]][, callback]):完成发送请求。
  • request.abort():终止当前的请求。
  • request.setTimeout(timeout,[callback]):为请求设置Socket超时时间。

Node实现http

服务器:

// 导入http模块
const http = require('http');


/*
创建http服务器:参数'req'是请求对象request,参数'res'是响应对象response
    'req':获取客户端的请求数据
    'res':向客户端发送响应数据
*/
const server = http.createServer((req,res) => {
    /*
    设置响应头信息:
        状态码:200 表示请求-响应成功
        content-type:响应信息的格式和字符集(编码格式)
    */
   res.writeHead(200,{'content-type':'text/html;charset=utf8'});
   res.write('<h2>Hello World!</h2>');
   res.end();
})


// 绑定端口并进行监听
server.listen(8080,() => {
    console.log('服务器在8080端口上进行监听!')
})

客户端:

// 导入HTTP模块
const http = require('http');

// 导入querystring模块
const querystring = require('querystring');

// 创建请求数据:通过querystring模块的stringify方法将请求数据转换为JSON格式
const postData = querystring.stringify({'msg':'你好,我是http客户端'});

// 创建请求的配置信息:服务器地址、端口、请求资源地址、请求方式、请求头信息
const options = {
    hostname: '127.0.0.1',
    port: 8080,
    path: '/upload',
    method: 'post',
    headers: {
        'Content-type': 'application/x-www-form-urlencoded;charset=utf-8',
        'Contnet-Length': Buffer.byteLength(postData)
    }
}

// 向服务器发送请求:创建请求对象
const req = http.request(options,(res) => {
    console.log(`状态码:${res.statusCode}`);
    console.log(`响应头信息:${JSON.stringify(res.headers)}`);
    res.setEncoding('utf-8');
    res.on('data',chunk => {
        console.log('响应体:'+chunk);
    })
    res.on('end',() => {
        console.log('请求结束');
    })
    res.on('error',(err) => {
        console.log(err);
    })
})

// 将请求数据写入请求体
req.write(postData);

// 请求结束
req.end();

在这里插入图片描述在这里插入图片描述

HTTP服务器获取并解析GET请求内容

服务器:

const http = require('http');
const url = require('url');
const queryString = require('querystring');

// 创建get服务器
var server = http.createServer((req,res) => {
    // 对客户端的url进行解码
    let reqUrl = decodeURI(req.url);

    // 将url字符串转换为url对象
    reqUrl = url.parse(reqUrl);

    let params = reqUrl.query.split('&');
    console.log(params[0]);

    res.end('提交成功!');
});

// 绑定并监听端口
server.listen(8080);

客户端:

const http = require('http');

// 设置请求的配置信息
const options = {
    hostname: '127.0.0.1',
    port: 8080,
    path: encodeURI('/index.html?age=12&name=张三')
}

// 创建get请求对象向服务器发送get请求
var geter = http.get(options,res => {
    res.setEncoding('utf8');
    res.on('data',chunk => {
        console.log('响应信息:'+chunk.toString());
    })
})

geter.on('error',err => {
    console.log(err.message);
})

在这里插入图片描述
在这里插入图片描述

HTTP服务器获取并解析POSt请求内容

服务器:

const http = require('http');
const queryString = require('querystring');

// 创建post请求的服务器对象
const server = http.createServer((req,res) => {
    // 'data'变量用来接收客户端向服务器发送的请求数据
    let data = '';

    // 参数'chunk'中存放的是客户端向服务器发送的请求数据,是二进制格式
    // 参数'chunk'在和变量'data'连接时自动转换为字符串
    req.on('data',chunk => {
        data += chunk;
    })

    // 给请求对象'req'绑定'end'事件,当请求结束时触发该事件
    req.on('end', () => {
        data = decodeURI(data); //对请求数据进行解码
        console.log('请求数据:'+data);
        // 将请求数据转换为对象
        let dataObj = queryString.parse(data);  
        console.log('姓名:',dataObj.name);
        console.log('学历:',dataObj.title);
        res.end('提交成功!');
    })
})

server.listen(8080);

客户端:

const http = require('http');
const queryString = require('querystring');

// 将要提交给服务器的数据转换为JSON格式
var postData = queryString.stringify({
    'name': '关羽',
    'title': '博士'
})

// 创建配置信息
const options = {
    hostname: '127.0.0.1',
    port: 8080,
    method: 'post'
}

// 创建post请求对象
const req = http.request(options,res => {
    res.setEncoding('utf-8');
    res.on('data',chunk => {
        console.log('响应数据:'+chunk.toString());
    })
})

// 将请求数据写入到请求对象中
req.write(postData);

// 结束请求
req.end();

在这里插入图片描述
在这里插入图片描述

通过Node的http模块访问服务器端的静态资源

静态资源(css文件、图像、html文件)

  • 创建一个Node项目

  • 项目目录结构
    在这里插入图片描述

  • main.css

    body{
    background-color: pink;
    text-align: center;
    }

  • index.html

    首页

    首页

  • loginhtml

    登录

    登录

  • 404.html

    404

    404 资源不能在

  • server.js

    const http = require(‘http’);
    const fs = require(‘fs’);
    const path = require(‘path’);

    //1.创建http服务器
    var server = http.createServer();

    //2.给http服务器绑定’request’事件
    server.on(‘request’,(req,res)=> {
    //2.1 获取客户端的url
    let url = req.url;

    console.log(__dirname);
    //2.2 对客户端的url进行判断,根据判断的结果读取不同的文件
    if(url === '/'){
        fs.readFile(path.join(__dirname,'/html/login.html'),'utf8',(err, data) =>{
            if(err){
                throw err;
            }
            res.end(data);
        })
    }else if(url === '/login'){
        fs.readFile(path.join(__dirname,'/html/login.html'),'utf8',(err, data) =>{
            if(err){
                throw err;
            }
            res.end(data);
        })
    }else if(url === '/css/main.css'){
        fs.readFile(path.join(__dirname,'/css/main.css'),'utf8',(err, data) =>{
            if(err){
                throw err;
            }
            res.end(data);
        })
    }else if(url === '/images/7.png'){
        fs.readFile(path.join(__dirname,'/images/7.png'),(err, data) =>{
            if(err){
                throw err;
            }
            res.end(data);
        })
    }else{
        fs.readFile(path.join(__dirname,'/html/404.html'),'utf8',(err, data) =>{
            if(err){
                throw err;
            }
            res.end(data);
        })
    }
    

    });

    //3.绑定端口,并进行监听
    server.listen(3000,()=> {
    console.log(‘服务器在3000端口上进行监听’);
    })

WebSocket

WebSocket概述

为什么需要WebSocket协议:

  • HTTP存在的问题:
    • 每次客户端和服务器端的交互都是一次HTTP的请求和应答的过程,增加了每次传输的数据量,浪费带宽资源。
    • 不是真正的实时技术,只是模拟实时的效果,轮询会造成同步延迟。
    • 编程比较复杂,尤其是要模拟比较真实的实时效果时。
  • WebSocket协议突破HTTP的局限性,节省服务器资源和带宽,解决两端的实时数据传输问题。

WebSocket协议的实现机制:

  • 由客户端发起握手,建立连接阶段必须依赖HTTP进行一次握手。两端之间的WebSocket连接建立的同时服务器完成了协议升级,由HTTP升级为WebSocket。连接会一直保持,直到客户端或者服务器任何一方主动关闭。
  • 进入数据交换阶段,客户端与服务器可以互相主动发送消息。此阶段数据直接通过TCP通道传输,不再依赖HTTP。WebSocket的数据传输是以帧(Frame)的形式传输的。
  • 关闭连接,可以由任意一端发起关闭连接的命令。
    在这里插入图片描述

WebSocket协议的应用场合:

  • 实时通信:聊天应用。
  • 实时展示和分析:典型的有实时计数器、图表、日志客户端等。
  • 文档协同:允许多个用户同时编辑一个文档,且用户能够看到每个用户做出的修改。
  • WebSocket协议不适合那些不支持HTML5或对HTML5支持不够充分的浏览器。

ws库

WebSocket库:ws、WebSocket-Node、faye-websocket-node和socket.io。

导入库
const WebSocket = require('ws')

WebSocket服务器

创建一个WebSocket服务器实例:
new WebSocket.Server(options[, callback])

WebSocket服务器内置事件:

  • close:服务器关闭时被触发
  • connection:成功握手连接时触发
  • error:发生错误时被触发,可注入一个Error对象
  • headers:握手前被触发,允许在发送HTTP头之前检查和修改标题
  • listening:绑定端口时被触发

WebSocket客户端

创建一个WebSocket客户端实例:

  • new WebSocket(address[, protocols][, options])

WebSocket客户端内置事件:

  • close:连接关闭时被触发,有两个参数code(状态码)和reason(原因)
  • error:发生错误时被触发,有一个参数error(错误)
  • message:接收到服务器消息时被触发,有一个参数data,表示接收到的数据,类型可以是字符串、Buffer、ArrayBuffer
  • open:连接建立时被触发

Node实现WebSocket

  • server.js

    // 1. 安装ws模块 npm install ws

    // 2. 导入ws模块
    const WebSocket = require(‘ws’);

    // 3. 创建WebSocket服务器并在8080端口监听
    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);
            }
        })
    })
    

    })

  • client.html

    聊天室
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bluepad

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值