Node.js服务器开发(1)
一、安装Nodejs
1下载安装node.js
下载安装:地址址http://www.nodejs.cn
使用node.exe来解释执行 写好的js代码
环境变量他会自动配置好
但是你使用第三库就还要一个环境变量,指定Node搜索第三方模块路劲
NODE_PATH是npm安装好的模块所在的搜索路劲.
NODE_PATH 值: %AppData%\npm\node_modules;
2.下载安装cygwin 然后 写一个hello
找打这个js文件目录
node js文件名 解释执行即可
二、事件循环和progress模块
Node.js事件循环
1.如果node.js没有要处理的事件了,那整个就结束.直接退出node
事件里面可以继续插入事件,如果有事件是一直要继续下去
那node就不会退出,每一次事件处理结束后,等待下一个事件的发生
一旦有事件发生就会调用回调函数.回调函数里还可以插入新的事件
2setTimeout插入一个计时器事件,单位为毫秒 触发一次结束.
setTimeout(function(){console.log("helloworld");},3000);
3setInterval插入一个不断循环的计时器事件.
setInterval(function(){console.log("helloworld");},1000*2);
Progress属性和事件
1.process模块用来与当前进程互动,获取相关操作系统相关信息
2.process是全局模块 全局变量不需要require
3.process.pid进程pid,version是node版本,platform平台,
title窗口或进程名称,argv控制台启动传入的参数,他是个字符串数组
execPath,node所在路劲, env获得系统的环境变量
重要方法
cwd 获取当前工作目录 uptime获取进程运行时间,
chdir这只当前的工作目录 ,
nextTick下一次循环的时候调用后没事循环事件开始前先调用它
4.监听exit事件,node退出会抛出exit事件,当用户监听这个事件
那么exit事件发生后会收到通知.
process.on("exit",function(){console.log("node退出");});
5.uncaughtException事件function(err){};
6.处理的时候遇到了异常,如果这个异常捕获,那么就继续
处理下一个事件,则否直接停止.
//没有定义的函数调用//解释器不会主动捕获异常,他就不会继续执行notfunction();
捕获异常 这样node就不会终止运行,
//当有异常发生立刻调用这个回调函数process.on("uncaughtException",function(err){console.log("捕获到异常:"+err);});
三、Node.js Net模块使用TCP通讯
在node.js里所有的net模块 都是异步的,所以都要通过
绑定事件,来获取相应的操作是否完成.
server服务器
只要创建一个监听服务器,然后调用监听函数即可
每次有新的连接产生后就调用connection事件
他的参数就是和客户端通信的socket一个net.Socket实例
这个实例里就要绑定 error错误事件,close客户端关闭事件
还有就是data客户端发送数据的事件,这个事件发送的数据
默认参数data是二进制的,你要调用setEncoding设置编码
//引入net模块varnet=require("net");//创建一个net.Server用来监听//这个API是创建一个新的TCP或IPC服务。//当有连接请求会调用这个匿名回调函数varserver=net.createServer((client_sock)=>{//收到客户端接入的回调函数//client_spcl就是与客户端通讯的socketconsole.log("clientcomming");});//指示监听端口为connections启动一个server监听//server.listen(options[,callback])//这个函数是异步的,server开始监听,listening事件触发,//最后一个参数callback就是listening事件监听器.//如果exclusive是false(默认),//则集群的所有进程将使用相同的底层句柄,//允许共享连接处理任务node事件循环会一直等待在这console.log("开始等待客户端连接");server.listen({host:"127.0.0.1",//host:'localhost',port:6800,exclusive:true,});//绑定listening事件//当服务被绑定后调用也就是调用listen函数就调用server.on("listening",function(){console.log("startlistening...");});//绑定建立链接事件和客户端不同//这个会产生一个net.Socket新的实例//用来和客户端产生通讯的上面那个就是这个参数//其实就是封装了这个事件的回调函数server.on("connection",function(client_sock){console.log("新的链接建立了");//绑定客户端socket关闭事件client_sock.on("close",function(){console.log("客户端关闭连接");});//设置接受数据的编码//data默认是二进制格式、//这个二进制每一个值对应ASCLL码的十六进制值//调用这个底层就将他转出成utf8的字符串//然后传给你//设置成二进制//client_sock.setEncoding("hex");//这样会把这个Buffer对象转成二进制字符串给你client_sock.setEncoding("utf-8");////当客户端给服务器发数据的时候//绑定data事件当接收到数据时被触发//参数data是buffer或者string类型//数据的编码由socket.setEncoding()设定client_sock.on("data",function(data){console.log("接收到数据",data);});//监听错误事件通讯可能会出错client_sock.on("error",function(e){console.log("error",e);});});//绑定错误事件server.on("error",function(){console.log("listenererr");});//绑定关闭事件server.on("close",function(){//服务器关闭如果还有链接存在,直到所有连接关闭//这个事件才会被触发console.log("serverstoplistener");});//停止侦听连接//server.unref();//停止监听主动关闭socket//参数就是close事件的回调可以写在参数里都可以//他必须是在停止侦听之后调用//如果不这样的话服务器还是可以收到连接//server.close();
Client客户端
首先用ner.creatConnection或者net.connect创建连接到服务器
这时候你就要绑定connect的回调函数,一旦连接成功就会回调
close事件,socket关闭后触发, data事件,收到数据就触发
error事件,当socket有错误发生.
//引入net模块varnet=require("net");//链接服务器一旦链接成功第二个参数//就会立刻回调varc_sock=net.connect({port:6800,host:"127.0.0.1",},()=>{console.log("connectedtoserver!");});//这里绑定connect事件和上面那个效果相同//上面那个是被封装成回调函数了c_sock.on("connect",function(){console.log("connectsuccess!");//socket.write(data,[,encoding][,callback])//在socket上发送数据,第二个参数指定字符串编码默认UTF-8//如果发数据成功到内核的缓冲返回true,如果全部或部分//数据在用户内中排队,返回false,如果缓冲再次空闲则触发//drain事件,当数据最终写出之后,调用callback回调.//第二个参数和第三个参数是可选的c_sock.write("hellosocketserver");});//绑定错误事件c_sock.on("error",function(err){console.log("错误"+err);});//绑定关闭事件c_sock.on("close",function(){console.log("关闭socket");});
四、Node.js二进制数据和Buffer模块
在网络数据的传送过程中,所有的数据都是使用二进制传送的.
二进制
1.在计算机里存放的数据都是二进制的方式来存储
2.最小单位为字节,8位二进制-->bit
3.所有数据最终都是二进制的方式存放;
4.比如说你有一个字符串"ABCD" 因为这是几个英文单词,但是
无法直接把这个几个单词存到电脑里面,因为电脑只认识二进制的
0和1,这时候就要用到编码,用特定的数字表示特定的符号.
4.ASCLL编码,'A'-->65数据,把数据当字符,
也就是把字符A转出一个数据65,然后把65存进去.
5.
Int8/Uint8 一个字节的整数
Int16/Uint16 二个字节的整数
Int32/Uint32 4个字节的整数
Int/Uint 8个字节整数
Float4个字节小数, Double 8个字节的小数;
大尾和小尾
1.两个字节0x7766其中 77是高位,66是低位
2.尾指定是地址是低的地方,
3.小尾Lihe指的是低位的数据存在低地址的地方,高位存放在高地址的地方
4.大尾Bigger指的是高位的数据存在低地址的地方,低位存在在高地址的地方
5.计算机中的内存使用的就是小尾. 有的CPU则使用大尾.
6.4个字节的数据,存到内存的4个字节
小尾: LE高位的数据-->高地址字节的地方==高高低低
大尾: BE高位的数据-->地地址字节的地方==低高低高
Buffer Pool
1.node.js使用Buffer对象来存放二进制数据;
2.为了快速分配,先从Buffer池分配,如果分配不成功,再直接
向系统申请 Buffer pool 只能满足一定范围内的大小,
如过你申请的过大,那么他会直接向操作系统申请内存.
3.Buffer pool是为了提高内存分配的效率和利用率.
一些小内存首先会从Buffer pool里分配,分配成功直接返回这个内存
如果分配不成功,再向操作系统去申请,回收的时候直接丢给操作系统.
4.Buffer就为我们提供了,大小不大,但是分配频繁的内存,
做了一个缓存池,提高运行效率. 减少内存碎片.
5.创建一个Buffer对象 Buffer一旦分配大小,再也无法改变
如果这时候你使用越界,就会出现错误.
length属性获取Buffer对象的长度.
Buffer.alloc(); Buffer.allocUnsafe();Buffer.allocUnsafeSlow()
Buffer.from(array),Buffer.from(buf),Buffer.from(string)
//(1)分配10个字节//(2)会给这些内存一个初值,如果你每指定,//那么这个初值就是0//41十六进制从ASCLL码的41表示A////输出十个"41"41是十六进制varbuf=Buffer.alloc(10,'A');//这样也可以代表十六进制41//输出十个"41"41是十六进制buf=Buffer.alloc(10,0x41);//也可以是字符串buf=Buffer.alloc(10,"Hell");/////////Unsafe//(1)他会分配一个给定大小的Buffer内存//(2)不会对这些内存去赋初值的.//这个内存是随机的数据buf=Buffer.allocUnsafe(10);/////////UnsafeSlow//没有从缓冲池里面高效的分配//直接从操作系统分配,更慢所以叫Slow//Unsafe是没有初始化的内存buf=Buffer.allocUnsafeSlow(10);//获得Buffer对象的长度console.log(buf.length);/////////from(string)//更方便的创建方式类似于复制//分配一个BUffer对象,用来存放字符串的二进制.//输出结果是每个字母对应的十六进制ASCLL码buf=Buffer.from("HelloWorld");////////from(array)//输出的是每个数字十进制,对应的十六进制buf=Buffer.from([123,456,789,-1,45]);//////from(Buffer)//重新场景一个Buffer把原来buf的数据拷贝给新的varbuf2=Buffer.from(buf);console.log(buf2);/////读取其中的一个数据//输出的是123console.log(buf[0]);console.log(buf);
读写Buffer
1.Buffer读取字节buf[index]使用下标
这个索引是 0 到 length - 1,才是合法范围.
2.根据大大尾小尾来决定使用BE大尾/LE小尾
3.readFloatBE/readDoubleBE/readFloatLE/readDoubleLE
4.读/写整数:read/write
Int8/Uint 一个字节不存在大尾小尾.
Int16BE/Int16LE/UInt16BE/UInt16LE
Int32BE/Int32LE/UInt32BE/UInt32LE
IntBE/IntLE/UIntBE/UIntLE
floatBE/floatLE/doubleBE/doubleLE
写一个整数到Buffer里面
//写入4个字节大尾//value值,offset是从哪开始写//noAssert是否检查长度是不是有效范围,//用来检测内存越界,默认不用检测,提升性能.//writeInt32LE(value,offset,[.noAssert])buf.writeInt32BE(65535,0);//用十六进制表示0x0000ffff//这里输出的就是0000FFFF//因为他是大尾法写入,他的高位0000低位FFFF//大端法大尾把高位放低地址作为起始地址//所以输出的就是0000FFFFconsole.log(buf);
读取
//使用大尾读出来参数是从哪里开始读varvalue=buf.readInt32BE(0);console.log(value);
Buffer重要方法
1.Buffer.byteLength(str,encoding)返回字符对象
str可以说string,Buffer,Array,ArrayBuffer
对应的二进制长度.encoding如果是字符串,字符编码模式utf-8
也就是存下str需要多长字节.
varlen=Buffer.byteLength("HelloWorld");//输出10console.log(len);也可以是Buffer对象varlen=Buffer.byteLength(buf2);//输出5console.log(buf2);
2.交换swap16,swap32,swap64 大尾小尾数据变化
16是两个字节交换位置, 32是4个字节两个两个交换位置
64是前面4个和后面4个字节 交换位置
将buf解析为一个整数数组,并且以字节顺序原地进行交换
//16个字节varbufer=Buffer.alloc(4*4);bufer.writeInt32LE(65535,0);bufer.writeInt32LE(65535,4);bufer.writeInt32LE(65535,8);bufer.writeInt32LE(65535,12);//输出ffff00004个//并且是小尾存放console.log(bufer);
然后转换成大尾
bufer.swap32();//这里输出的就是0000ffff4个//就是转换成大端法,高位放地地址.console.log(bufer);
3.buffer.values() 遍历buf每个字节
for(varvluofbufer.values()){console.log(vlu);}
4.Buffer转字符串 buf.toString()
比如说二进制字符串
//参数是编码hex是二进制console.log(bufer.toString('hex'));
5.Buffer转Json字符串,
JSON.stringify(buf) buffer.toJSON
console.log(bufer.toJSON());
6.Buffer.fill 填充参数可以是字符 字符串 ×××
那这个buffer里所有数据都变成这个了
bufer.fill(23);
bufer.fill("ab")
如果未指定offset
和end
,则填充整个buf
。
这个简化使得一个Buffer
的创建与填充可以在一行内完成
例如填充ASCLL码 'A'
bufer.fill('A');
console.log(bufer);
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。