新聞中心
一、安裝Nodejs
1下載安裝node.js
下載安裝:地址址http://www.nodejs.cn
使用node.exe來解釋執(zhí)行 寫好的js代碼
環(huán)境變量他會自動配置好
但是你使用第三庫就還要一個環(huán)境變量,指定Node搜索第三方模塊路勁
NODE_PATH是npm安裝好的模塊所在的搜索路勁.
NODE_PATH 值: %AppData%\npm\node_modules;
2.下載安裝cygwin 然后 寫一個hello
找打這個js文件目錄
node js文件名 解釋執(zhí)行即可
二、事件循環(huán)和progress模塊
Node.js事件循環(huán)
1.如果node.js沒有要處理的事件了,那整個就結(jié)束.直接退出node
事件里面可以繼續(xù)插入事件,如果有事件是一直要繼續(xù)下去
那node就不會退出,每一次事件處理結(jié)束后,等待下一個事件的發(fā)生
一旦有事件發(fā)生就會調(diào)用回調(diào)函數(shù).回調(diào)函數(shù)里還可以插入新的事件
2setTimeout插入一個計時器事件,單位為毫秒 觸發(fā)一次結(jié)束.
setTimeout(function() { console.log("hello world"); },3000);
3setInterval插入一個不斷循環(huán)的計時器事件.
setInterval(function () { console.log("hello world"); },1000*2);
Progress屬性和事件
1.process模塊用來與當(dāng)前進(jìn)程互動,獲取相關(guān)操作系統(tǒng)相關(guān)信息
2.process是全局模塊 全局變量不需要require
3.process.pid進(jìn)程pid,version是node版本,platform平臺,
title窗口或進(jìn)程名稱,argv控制臺啟動傳入的參數(shù),他是個字符串?dāng)?shù)組
execPath,node所在路勁, env獲得系統(tǒng)的環(huán)境變量
重要方法
cwd 獲取當(dāng)前工作目錄 uptime獲取進(jìn)程運(yùn)行時間,
chdir這只當(dāng)前的工作目錄 ,
nextTick下一次循環(huán)的時候調(diào)用后沒事循環(huán)事件開始前先調(diào)用它
4.監(jiān)聽exit事件,node退出會拋出exit事件,當(dāng)用戶監(jiān)聽這個事件
那么exit事件發(fā)生后會收到通知.
process.on("exit",function(){ console.log("node退出"); });
5.uncaughtException事件function(err){};
6.處理的時候遇到了異常,如果這個異常捕獲,那么就繼續(xù)
處理下一個事件,則否直接停止.
//沒有定義的函數(shù) 調(diào)用 //解釋器 不會主動捕獲異常,他就不會繼續(xù)執(zhí)行 notfunction();
捕獲異常 這樣node就不會終止運(yùn)行,
//當(dāng)有異常發(fā)生 立刻調(diào)用這個回調(diào)函數(shù) process.on("uncaughtException",function(err){ console.log("捕獲到異常:"+err); });
三、Node.js Net模塊使用TCP通訊
在node.js里所有的net模塊 都是異步的,所以都要通過
綁定事件,來獲取相應(yīng)的操作是否完成.
server服務(wù)器
只要創(chuàng)建一個監(jiān)聽服務(wù)器,然后調(diào)用監(jiān)聽函數(shù)即可
每次有新的連接產(chǎn)生后就調(diào)用connection事件
他的參數(shù)就是和客戶端通信的socket一個net.Socket實(shí)例
這個實(shí)例里就要綁定 error錯誤事件,close客戶端關(guān)閉事件
還有就是data客戶端發(fā)送數(shù)據(jù)的事件,這個事件發(fā)送的數(shù)據(jù)
默認(rèn)參數(shù)data是二進(jìn)制的,你要調(diào)用setEncoding設(shè)置編碼
//引入net模塊 var net = require("net"); //創(chuàng)建一個net.Server用來監(jiān)聽 //這個API是創(chuàng)建一個新的TCP或IPC服務(wù)。 //當(dāng)有連接請求 會調(diào)用這個匿名回調(diào)函數(shù) var server = net.createServer((client_sock)=>{ //收到客戶端接入的回調(diào)函數(shù) //client_spcl就是與客戶端通訊的socket console.log("client comming"); }); //指示監(jiān)聽端口 為 connections 啟動一個 server 監(jiān)聽 //server.listen(options[, callback]) //這個函數(shù)是異步的,server開始監(jiān)聽,listening事件觸發(fā), //最后一個參數(shù)callback就是listening事件監(jiān)聽器. //如果 exclusive 是 false(默認(rèn)), //則集群的所有進(jìn)程將使用相同的底層句柄, //允許共享連接處理任務(wù) node事件循環(huán)會一直等待在這 console.log("開始等待客戶端連接"); server.listen({ host: "127.0.0.1", //host: 'localhost', port: 6800, exclusive: true, }); //綁定listening 事件 //當(dāng)服務(wù)被綁定后調(diào)用 也就是調(diào)用listen函數(shù)就調(diào)用 server.on("listening",function(){ console.log("start listening ..."); }); //綁定建立鏈接事件 和客戶端不同 //這個會產(chǎn)生一個net.Socket新的實(shí)例 //用來和客戶端產(chǎn)生通訊的 上面那個 就是這個參數(shù) //其實(shí)就是封裝了這個事件 的回調(diào)函數(shù) server.on("connection",function(client_sock){ console.log("新的鏈接建立了"); //綁定 客戶端socket 關(guān)閉 事件 client_sock.on("close",function(){ console.log("客戶端關(guān)閉連接"); }); //設(shè)置 接受數(shù)據(jù)的編碼 //data默認(rèn)是二進(jìn)制格式、 //這個二進(jìn)制每一個值 對應(yīng)ASCLL碼的十六進(jìn)制值 //調(diào)用這個底層就將他轉(zhuǎn)出成utf8的字符串 //然后傳給你 //設(shè)置成二進(jìn)制 //client_sock.setEncoding("hex"); //這樣會把這個Buffer對象轉(zhuǎn)成二進(jìn)制字符串給你 client_sock.setEncoding("utf-8"); ////當(dāng)客戶端給 服務(wù)器發(fā)數(shù)據(jù)的時候 //綁定data事件 當(dāng)接收到數(shù)據(jù)時被觸發(fā) //參數(shù)data是buffer或者string類型 //數(shù)據(jù)的編碼由socket.setEncoding()設(shè)定 client_sock.on("data",function(data){ console.log("接收到數(shù)據(jù)",data); }); //監(jiān)聽錯誤事件 通訊可能會出錯 client_sock.on("error",function(e){ console.log("error",e); }); }); //綁定錯誤事件 server.on("error",function(){ console.log("listener err"); }); //綁定關(guān)閉事件 server.on("close",function(){ //服務(wù)器關(guān)閉 如果還有鏈接存在,直到所有連接關(guān)閉 //這個事件才會被觸發(fā) console.log("server stop listener"); }); //停止偵聽 連接 // server.unref(); //停止監(jiān)聽 主動關(guān)閉socket //參數(shù) 就是close事件的回調(diào) 可以寫在參數(shù)里都可以 //他必須是在停止偵聽之后 調(diào)用 //如果不這樣的話 服務(wù)器 還是可以收到連接 //server.close();
Client客戶端
首先用ner.creatConnection或者net.connect創(chuàng)建連接到服務(wù)器
這時候你就要綁定connect的回調(diào)函數(shù),一旦連接成功就會回調(diào)
close事件,socket關(guān)閉后觸發(fā), data事件,收到數(shù)據(jù)就觸發(fā)
error事件,當(dāng)socket有錯誤發(fā)生.
//引入net模塊 var net = require("net"); //鏈接服務(wù)器 一旦鏈接成功第二個參數(shù) //就會立刻回調(diào) var c_sock = net.connect({ port:6800, host:"127.0.0.1", },()=>{ console.log("connected to server!"); }); //這里綁定connect事件 和上面那個效果相同 //上面那個是 被封裝成回調(diào)函數(shù)了 c_sock.on("connect",function(){ console.log("connect success!"); //socket.write(data,[,encoding][,callback]) //在socket上發(fā)送數(shù)據(jù),第二個參數(shù)指定字符串編碼默認(rèn)UTF-8 //如果發(fā)數(shù)據(jù)成功到內(nèi)核的緩沖返回true,如果全部或部分 //數(shù)據(jù)在用戶內(nèi)中排隊(duì),返回false,如果緩沖再次空閑則觸發(fā) //drain事件, 當(dāng)數(shù)據(jù)最終寫出之后,調(diào)用callback回調(diào). //第二個參數(shù) 和 第三個參數(shù)是可選的 c_sock.write("hello socket server"); }); //綁定錯誤事件 c_sock.on("error",function(err){ console.log("錯誤"+err); }); //綁定關(guān)閉事件 c_sock.on("close",function(){ console.log("關(guān)閉socket"); });
四、Node.js二進(jìn)制數(shù)據(jù)和Buffer模塊
在網(wǎng)絡(luò)數(shù)據(jù)的傳送過程中,所有的數(shù)據(jù)都是使用二進(jìn)制傳送的.
二進(jìn)制
1.在計算機(jī)里存放的數(shù)據(jù)都是二進(jìn)制的方式來存儲
2.最小單位為字節(jié),8位二進(jìn)制-->bit
3.所有數(shù)據(jù)最終都是二進(jìn)制的方式存放;
4.比如說你有一個字符串"ABCD" 因?yàn)檫@是幾個英文單詞,但是
無法直接把這個幾個單詞存到電腦里面,因?yàn)殡娔X只認(rèn)識二進(jìn)制的
0和1,這時候就要用到編碼,用特定的數(shù)字表示特定的符號.
4.ASCLL編碼,'A'-->65數(shù)據(jù),把數(shù)據(jù)當(dāng)字符,
也就是把字符A轉(zhuǎn)出一個數(shù)據(jù)65,然后把65存進(jìn)去.
5.
Int8/Uint8 一個字節(jié)的整數(shù)
Int16/Uint16 二個字節(jié)的整數(shù)
Int32/Uint32 4個字節(jié)的整數(shù)
Int/Uint 8個字節(jié)整數(shù)
Float4個字節(jié)小數(shù), Double 8個字節(jié)的小數(shù);
大尾和小尾
1.兩個字節(jié)0x7766其中 77是高位,66是低位
2.尾指定是地址是低的地方,
3.小尾Lihe指的是低位的數(shù)據(jù)存在低地址的地方,高位存放在高地址的地方
4.大尾Bigger指的是高位的數(shù)據(jù)存在低地址的地方,低位存在在高地址的地方
5.計算機(jī)中的內(nèi)存使用的就是小尾. 有的CPU則使用大尾.
6.4個字節(jié)的數(shù)據(jù),存到內(nèi)存的4個字節(jié)
小尾: LE高位的數(shù)據(jù)-->高地址字節(jié)的地方==高高低低
大尾: BE高位的數(shù)據(jù)-->地地址字節(jié)的地方==低高低高
Buffer Pool
1.node.js使用Buffer對象來存放二進(jìn)制數(shù)據(jù);
2.為了快速分配,先從Buffer池分配,如果分配不成功,再直接
向系統(tǒng)申請 Buffer pool 只能滿足一定范圍內(nèi)的大小,
如過你申請的過大,那么他會直接向操作系統(tǒng)申請內(nèi)存.
3.Buffer pool是為了提高內(nèi)存分配的效率和利用率.
一些小內(nèi)存首先會從Buffer pool里分配,分配成功直接返回這個內(nèi)存
如果分配不成功,再向操作系統(tǒng)去申請,回收的時候直接丟給操作系統(tǒng).
4.Buffer就為我們提供了,大小不大,但是分配頻繁的內(nèi)存,
做了一個緩存池,提高運(yùn)行效率. 減少內(nèi)存碎片.
5.創(chuàng)建一個Buffer對象 Buffer一旦分配大小,再也無法改變
如果這時候你使用越界,就會出現(xiàn)錯誤.
length屬性獲取Buffer對象的長度.
Buffer.alloc(); Buffer.allocUnsafe();Buffer.allocUnsafeSlow()
Buffer.from(array),Buffer.from(buf),Buffer.from(string)
//(1)分配10個字節(jié) //(2)會給這些內(nèi)存一個初值,如果你每指定, //那么這個初值就是0 //41十六進(jìn)制從ASCLL碼的41表示A ////輸出十個 "41" 41是十六進(jìn)制 var buf = Buffer.alloc(10,'A'); //這樣也可以 代表十六進(jìn)制 41 //輸出十個 "41" 41是十六進(jìn)制 buf = Buffer.alloc(10,0x41); //也可以是字符串 buf = Buffer.alloc(10,"Hell"); /////////Unsafe //(1)他會分配一個給定大小的Buffer內(nèi)存 //(2)不會對這些內(nèi)存去賦初值的. //這個內(nèi)存是隨機(jī)的數(shù)據(jù) buf = Buffer.allocUnsafe(10); /////////UnsafeSlow //沒有從緩沖池里面高效的分配 //直接從操作系統(tǒng)分配,更慢所以叫Slow //Unsafe 是沒有初始化的內(nèi)存 buf = Buffer.allocUnsafeSlow(10); //獲得Buffer對象的長度 console.log(buf.length); /////////from(string) //更方便的創(chuàng)建方式類似于復(fù)制 //分配一個BUffer對象,用來存放字符串的二進(jìn)制. //輸出結(jié)果是每個字母對應(yīng)的十六進(jìn)制ASCLL碼 buf = Buffer.from("HelloWorld"); ////////from(array) //輸出的是每個數(shù)字十進(jìn)制,對應(yīng)的十六進(jìn)制 buf = Buffer.from([123,456,789,-1,45]); //////from(Buffer) //重新場景一個Buffer把原來buf的數(shù)據(jù)拷貝給新的 var buf2 = Buffer.from(buf); console.log(buf2); /////讀取其中的一個數(shù)據(jù) //輸出的是123 console.log(buf[0]); console.log(buf);
讀寫B(tài)uffer
1.Buffer讀取字節(jié)buf[index]使用下標(biāo)
這個索引是 0 到 length - 1,才是合法范圍.
2.根據(jù)大大尾小尾來決定使用BE大尾/LE小尾
3.readFloatBE/readDoubleBE/readFloatLE/readDoubleLE
4.讀/寫整數(shù):read/write
Int8/Uint 一個字節(jié)不存在大尾小尾.
Int16BE/Int16LE/UInt16BE/UInt16LE
Int32BE/Int32LE/UInt32BE/UInt32LE
IntBE/IntLE/UIntBE/UIntLE
floatBE/floatLE/doubleBE/doubleLE
寫一個整數(shù)到Buffer里面
//寫入4個字節(jié) 大尾 //value值,offset是從哪開始寫 //noAssert是否檢查長度是不是有效范圍, //用來檢測內(nèi)存越界,默認(rèn)不用檢測,提升性能. //writeInt32LE(value,offset,[.noAssert]) buf.writeInt32BE(65535,0); //用十六進(jìn)制表示 0x0000ffff //這里輸出的就是00 00 FF FF //因?yàn)樗谴笪卜▽懭?他的高位0000 低位FFFF //大端法 大尾把高位放低地址作為起始地址 //所以輸出的就是 00 00 FF FF console.log(buf);
讀取
//使用大尾讀出來 參數(shù)是從哪里開始讀 var value = buf.readInt32BE(0); console.log(value);
Buffer重要方法
1.Buffer.byteLength(str,encoding)返回字符對象
str可以說string,Buffer,Array,ArrayBuffer
對應(yīng)的二進(jìn)制長度.encoding如果是字符串,字符編碼模式utf-8
也就是存下str需要多長字節(jié).
var len = Buffer.byteLength("HelloWorld"); //輸出10 console.log(len); 也可以是Buffer對象 var len = Buffer.byteLength(buf2); //輸出5 console.log(buf2);
2.交換swap16,swap32,swap64 大尾小尾數(shù)據(jù)變化
16是兩個字節(jié)交換位置, 32是4個字節(jié)兩個兩個交換位置
64是前面4個和后面4個字節(jié) 交換位置
將buf解析為一個整數(shù)數(shù)組,并且以字節(jié)順序原地進(jìn)行交換
//16個字節(jié) var bufer = Buffer.alloc(4*4); bufer.writeInt32LE(65535,0); bufer.writeInt32LE(65535,4); bufer.writeInt32LE(65535,8); bufer.writeInt32LE(65535,12); //輸出ffff0000 4個 //并且是小尾 存放 console.log(bufer);
然后轉(zhuǎn)換成大尾
bufer.swap32(); //這里輸出的就是0000 ffff 4個 //就是轉(zhuǎn)換成大端法,高位放地地址. console.log(bufer);
3.buffer.values() 遍歷buf每個字節(jié)
for(var vlu of bufer.values()) { console.log(vlu); }
4.Buffer轉(zhuǎn)字符串 buf.toString()
比如說二進(jìn)制字符串
//參數(shù) 是編碼 hex是二進(jìn)制 console.log(bufer.toString('hex'));
5.Buffer轉(zhuǎn)Json字符串,
JSON.stringify(buf) buffer.toJSON
console.log(bufer.toJSON());
6.Buffer.fill 填充參數(shù)可以是字符 字符串 ×××
那這個buffer里所有數(shù)據(jù)都變成這個了
bufer.fill(23);
bufer.fill("ab")
如果未指定 offset
和 end
,則填充整個 buf
。
這個簡化使得一個 Buffer
的創(chuàng)建與填充可以在一行內(nèi)完成
例如填充ASCLL碼 'A'
bufer.fill('A');
console.log(bufer);
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無理由+7*72小時售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡單易用、服務(wù)可用性高、性價比高”等特點(diǎn)與優(yōu)勢,專為企業(yè)上云打造定制,能夠滿足用戶豐富、多元化的應(yīng)用場景需求。
當(dāng)前題目:Node.js服務(wù)器開發(fā)(1)-創(chuàng)新互聯(lián)
新聞來源:http://www.ef60e0e.cn/article/jhppp.html