第一节 Node.js课程介绍
1 查看系统中安装的Node.js版本
2 测试Node.js的控制台输出
3.1 在桌面新建test.js文件
3.2 通过Node.js 交互环境运行文件
笔记
一个js文件就是一个模块,而包是一个文件夹,包内必须包含一个JSON文件,命名为package.json。
bin文件夹:二进制文件
lib文件夹:js文件
doc文件夹:文档
test文件夹:单元测试
package.json
第二节 Node.js模块
一、暴露一个文件里的多个函数
exports.引用名(自定义) = 函数名;
exports.引用名(自定义) = 函数名;
……
mymodule.js
index.js
结果
二、暴露一个文件里的一个函数
module.exports = 函数名;
mymodule.js
index.js
结果
笔记
npm init //创建package.json文件
package.json
npm search express //搜索express包
npm install -g express //安装包,-g即global全局安装
npm updata express //更新包
npm uninstall express //卸载包
第三节 Node.js Events模块
一、添加监听器
emitter.addListener(event,listener)
emitter.on(event,listener)
1.1 新建test.js
1.2 运行代码
1.3 在浏览器输入'127.0.0.1337'每刷新一次会出现一个'shiyanlou'
二、只执行一次的监听器
emitter.once(event,listener)
2.1 新建test2.js
2.1 刷新浏览器,不再出现'shiyanlou'
三、移除监听器
emmiter.removeListener(event,listener)
3.1 新建test3.js
3.2 运行代码
3.3 出现了'shiyanlou',没有出现'Hello World'
四、移除所有监听器
emmiter.removeAllListeners([event])
4.1 新建test4.js
4.2 运行代码
4.3 只出现了'shiyanlou'
五、设置监听器最大绑定数
emitter.setMaxListners(n)
默认情况,超过10个就会警告提示
n = 0,无限制
六、自定义事件
emitter.emit(event,[arg1],[arg2],[...])
6.1 新建test5.js
6.2 运行及结果
七、查看事件绑定的监听器个数
EventEmitter.listenerCount(emitter,event)
7.1 新建test6.js
7.2 运行及结果
第四节 Node.js fs模块
一、异步和同步
fs.unlink(filename,callback); //异步
异步实例
fs.unlinkSync(filename); //同步
同步实例
二、readFile读取文件
fs.readFile(filename,[options],callback)
fs.readFile参数
原始二进制数据在缓冲区的内容
2.1 新建text.txt
2.2 新建readfile.js
2.3 运行及结果
使用toString()或者设置输出编码,修改readFile.js
text.js
运行及结果
三、writeFile写入文件
fs.writeFile(filename,data,[options],callback)
fs.write参数
3.1 新建writeFile.js
3.1.1 运行及结果
3.1.2 运行及结果
如果要追加数据到文件,可以传递一个flag参数
r :read
w :write
a :append
……
flag:a
运行及结果
四、使用fs.read和fs.write读写文件
fs.open(path,flags,[mode],callback) 打开文件
mode:文件的权限,默认值0666
flags的值
fs.close(fd,[callback]) 关闭文件
fd:所打开文件的文件描述符
4.1 fs.read()
fs.read(fd,buffer,offset,length,position,callback)
fs.read参数
4.1.1 新建testread.txt
4.1.2 新建read.js
4.1.3 运行及结果
4.2 fs.write()
fs.write(fd,buffer,offset,length,position,callback)
4.2.1 新建write.js
4.2.2.1 运行及结果
4.2.2.2 运行及结果
遇到的问题
在实验4.2中
修改后的代码
文档中的实验代码是fs.write(fd,buffer,0,6,0……),实际上应该只写入了‘shiyan’
本意应该是输出写入的内容
但是,如上所述的read代码,无论写入多少位内容,都会输出‘shiyanlou’,所以为了保持一致,我将源码进行了修改。
五、目录操作
5.1 创建目录
fs.mkdir(path,[mode],callback)
path:需要创建的目录
mode:目录的权限
fs.rmdir(path,mkdir)
只能删除空目录
5.1.1 新建mkdir.js
5.1.2 运行及结果
5.2 读取目录
fs.readdir(path,callback)
5.2.1 新建readdir.js
5.2.2 在newdir文件夹中新建'dir1文件夹'和'file1文件'
5.2.3 运行及结果
第五节 Node.js的http模块
一、创建 http server
1.1 通过Node.js创建(简单方式)
1.1.1 新建 demo.js
1.1.2 运行及结果
1.2 复杂方式
新建app文件夹,在app文件夹中新建server.js,代码如下:
/*
创建 http server
*/
// 加载所需模块
var http = require('http');
var url = require('url');
var fs = require('fs');
// 设置ip和端口
// 实际应用中,可以把这些写到配置文件中
var host = '127.0.0.1',
port = 8080;
// 创建http server
function start(route, handle) {
// 参数
// route 判断url是否存在,存在则调用handle处理,不存在则返回404
// handle 处理不同的url请求
// 处理request请求
function onRequest(req, res) {
// 使用url.parse()方法解析url
// 它会把url string转化为一个object
// 这样我们就可以很方便的获取url中的host、port、pathname等值了
var pathname = url.parse(req.url).pathname;
console.log('Request for ' + pathname + ' received.');
// 判断并处理不同url请求
// 后面介绍此方法
route(handle, pathname, res, req);
}
// 使用http.createSserver()方法创建http server
// 并传入onRequest()方法
// 然后使用listen()方法监听指定地址
http.createServer(onRequest).listen(port, host);
console.log('Server has started and listening on ' + host + ':' + port);
}
// 导出 start 方法
exports.start = start;
二、创建路由
2.1 在app文件夹中新建router.js,代码如下:
var fs = require('fs');
// 路由函数
// 处理不同url的请求
// 并返回相应内容
function route(handle, pathname, res, req) {
console.log('About to route a request for ' + pathname);
// 判断url是否存在特定处理函数
// 存在则调用handle处理
// 不存在则返回404页面
if (typeof handle[pathname] === 'function') {
// handle用于处理不同的url请求
handle[pathname](res, req);
} else {
console.log('No request handler found for ' + pathname);
// 读取404页面
// 所有页面都存放在view文件夹下
var content = fs.readFileSync('./views/404.html');
res.writeHead(404, {'Content-Type': 'text/html'});
res.write(content);
res.end();
}
}
// 导出route方法
exports.route = route;
2.2 在app文件夹中新建requestHandlers.js文件,代码如下:
// 处理url请求
// 读取文件,输出到response
var fs = require('fs');
// home.html主页
function home(res) {
console.log('Request handler "home" was called.');
// 读取home.html文件
var content = fs.readFileSync('./views/home.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(content);
res.end();
}
// about.html关于页面
function about(res) {
console.log('Request handler "about" was called.');
// 读取about.html文件
var content = fs.readFileSync('./views/about.html');
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(content);
res.end();
}
// 导出页面处理函数
exports.home = home;
exports.about = about;
三、创建主程序
3.1 在app文件夹新建main.js文件,代码如下:
// 主程序
// 引入server,router及requestHandler
var server = require('./server');
var router = require('./router');
var requestHandlers = require('./requestHandlers');
// 保存url处理方法
var handle = {};
handle['/'] = requestHandlers.home;
handle['/about'] = requestHandlers.about;
// 启动http server
server.start(router.route, handle);
四、创建HTML文件
在app文件夹中新建views文件夹,在views文件夹中,新建home.html文件、about.html文件和404.html文件。
4.1 home.html
Home pagehome page
4.2 about.html
About pageabout page
4.3 404.html
404 page404 page not found
五、运行及结果
5.1 运行main.js
5.2.1 地址栏输入127.0.0.1:8080
5.2.2 地址栏输入127.0.0.1:8080/about
5.2.3 地址栏输入127.0.0.1:8080/others
第六节 Node.js中的网络编程
一、TCP Server
net模块通过net.createServer方法创建TCP服务器,通过net.connect方法创建客户端去连接服务器。
1.1 新建server.js
var net = require('net');
// 创建TCP服务器
var server = net.createServer(function (socket) {
console.log('client connected');
// 监听客户端的数据
socket.on('data', function (data) {
console.log('server got datta from client:', data.toString());
});
// 监听客户端断开连接事件
socket.on('end', function (data) {
console.log('connection closed');
});
// 发送数据给客户端
socket.write('Hello\r\n');
});
// 启动服务
server.listen(8080, function () {
console.log('server bound');
});
1.2 新建 client.js
var net = require('net');
// 连接服务器
var client = net.connect({port: 8080}, function () {
console.log('connected to server');
client.write('World!\r\n');
});
// 接收服务端的数据
client.on('data', function (data) {
console.log('client got data from server:', data.toString());
// 断开连接
client.end();
});
// 断开连接
client.on('end', function () {
console.log('disconneected from server');
});
1.3 运行及结果
先在一个终端 运行server.js
再在另一个终端 运行client.js
1.3.1 server.js结果
1.3.2 client.js结果
二、简易聊天室
2.1 服务端——新建chatServer.js,代码如下:
var net = require('net');
// 创建TCP服务器
var server = net.createServer();
// 存储所有客户端socket
var sockets = [];
// 接受客户端连接请求
server.on('connection', function (socket) {
console.log('Got a new connection');
// 接收所有的用户连接(因为是聊天室,允许多个客户端用户同时连接)
sockets.push(socket);
// 获取客户端发送过来的数据
socket.on('data', function (data) {
console.log('Got data:', data.toString());
// 服务器广播数据,把来自客户端的数据转发送给其他所有客户端
sockets.forEach(function (otherSocket) {
if (otherSocket !== socket) {
otherSocket.write(data);
}
});
});
// 把需要关闭连接的客户端从服务器广播列表中给删除掉
socket.on('close', function () {
console.log('A client connection closed');
var index = sockets.indexOf(socket);
sockets.splice(index, 1);
});
});
server.on('error', function (err) {
console.log('Server error:', err.message);
});
server.on('close', function () {
console.log('Server closed');
});
server.listen(8080);
2.2 客户端,新建chatClient.js,代码如下:
var net = require('net');
process.stdin.resume();
process.stdin.setEncoding('utf8');
var client = net.connect({port: 8080}, function () {
console.log('Connected to server');
// 获取输入的字符串
console.log('input:');
process.stdin.on('data', function (data) {
// 发送输入的字符串到服务器
console.log('input:');
client.write(data);
// 输入'close'字符串时关闭连接
if (data == 'close\n\n') {
client.end();
}
});
});
// 获取服务器端发送过来的数据
client.on('data', function (data) {
console.log('Other user\'s input', data.toString());
});
client.on('end', function () {
console.log('Disconnected from server');
// 退出客户端程序
process.exit();
});
2.3 运行及结果
先在一个终端 运行chatServer.js
再在另一个终端 运行chatClient.js
再在再在另一个终端 运行chatClient.js
服务器端
客户端-1
客户端-2
遇到的问题
从运行结果截图可以看出,能正常聊天,但是输入‘close’时却无法正常退出!
三、UDP Server
3.1 服务端——新建udpServer.js,代码如下:
var dgram = require('dgram');
var server = dgram.createSocket('udp4');
server.on('error', function (err) {
console.log('serevr error:\n' + err.stack);
server.close();
});
// 接收来自客户端的消息
server.on('message', function (msg, rinfo) {
console.log('server got:' + msg.toString() + 'from' + rinfo.port);
});
// 监听服务
server.on('listening',function(){
var address = server.address();
console.log('server listening on '+address.address+':'+address.port);
});
server.bind(41234);
// server listening 0.0.0..0:41224
3.2 客户端——新建udpClient.js,代码如下:
var dgram = require('dgram');
var client = dgram.createSocket('udp4');
// 发送的消息必须通过Buffer创建
var message = new Buffer('hello shiyanlou!\n');
client.send(message, 0, message.length, 41234, 'localhost', function (err, bytes) {
client.close();
});
3.3 运行及结果
先在一个终端 运行updServer.js
再在另一个终端 运行udpClient.js
服务端
客户端
笔记
作为web服务器软件,Node.js提供了net模块用于tcp通信,dgram模块用于udp通信
net.createServer()用于创建tcp监听服务器,net.connect()用于客户端连接tcp服务器
dgram模块通过dgram.createSocket()创建udp socket,通过bind()监听特定端口,通过send()向特定socket发送信息
第七节 Node.js中的进程
process模块用于提供和程序主程序有关的功能
child_process用于创建子程序
cluster用于处理集群相关编程
一、process模块
1.1 退出事件(exit)
exit事件的回调函数中接收同步操作,并且回调函数只接受一个参数
在exit事件之前还有一个beforeExit事件会被触发,在beforeExit的回调函数中可以异步操作
通过process.exit()退出程序或者因为发生错误而退出程序是不会触发beforeExit事件的
当有错误未被捕获时,就会触发uncauhgtException事件
新建try-exit.js,代码如下:
process.on('exit', function (code) {
setTimeout(function () {
console.log('This will not run');
}, 0);
console.log('exit code', code);
});
运行结果
上述代码中,setTimeout方法中的回调函数不会被执行
1.2 信号事件
信号事件就是接受到某个特定信号才会被触发的事件。
新建sigint.js,代码如下:
process.stdin.resume();
process.on('SIGINT', function () {
console.log('Got SIGINT.');
});
先运行,按Ctrl-C触发‘SIGINT’事件
1.3 属性
IO 输入输出主要有三个
process.stdin // 标准输入
process.stdout // 标准输出
process.stderr // 标准错误
遇到的问题
新建stdin.js,源代码如下:
process.stdin.setEncoding('utf8');
process.stdin.on('readable', function() {
var chunk = process.stdin.read();
if (chunk !== null) {
process.stdout.write('data: ' + chunk);
}
});
process.stdin.on('end', function() {
process.stdout.write('end');
});
运行结果
当无内容输入时,可触发end事件,但结果里按回车没有触发,因为'\n'算两个字符,所以修改代码如下:
process.stdin.setEncoding('utf8');
process.stdin.on('readable', () => {
var chunk = process.stdin.read();
// 新增的代码
if (typeof chunk === 'string') {
chunk = chunk.slice(0, -2);
process.stdout.write(`stringLength:${chunk.length}\n`);
}
if (chunk === '') {
process.stdin.emit('end');
return;
}
if (chunk !== null) {
process.stdout.write(`data: ${chunk}\n`);
}
});
process.stdin.on('end', () => {
process.stdout.write('end');
});
运行结果
1.4 方法
process.cwd() //返回脚本运行工作目录
process.chdir() //切换工作目录
process.exit() //退出当前进程
process.on() //添加监听事件
...
二、child_process模块
用于创建子进程
2.1 child_process.spawn()方法
新建test_spawn.js,代码如下:
var spawn = require('child_process').spawn,
ls = spawn('ls', ['-lh', '/usr']);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('close', function (code) {
console.log('child process exited with code ' + code);
});
运行结果
2.2 child_process.exec()方法
在shell中运行一个命令,并缓存其输出
新建test_exec.js
运行结果
2.3 child_process.execFile()方法
与exec方法类似,执行特定程序文件,参数通过一个数组传递
新建test_execfiel.js
运行结果
2.4 child_process.fork()方法
fork('./sub.js')相当于spwan('node','./sub.js')
fork还会在父进程和子进程之间,建立一个通信管道,通过child.send()发送消息
2.4.1 新建main.js
2.4.2 新建sub.js
2.4.3 运行及结果
遇到的问题
在windows运行test_spawn.js
错误原因
所以该模块实验选择了实验楼配置的Linux环境
三、cluster模块
单个的Node实例运行在单个线程中。要发挥多核系统的能力,需要启动一个Node进程集群来处理负载。cluster模块就用于创建共享服务器端口的子进程。
3.1 新建 test_cluster.js
3.2 运行及结果