1. 程式人生 > >Node.js服務器開發(1)

Node.js服務器開發(1)

連接 解釋 ive tar box adding 一次 ror 沒有初始化

一、安裝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("hello world");
},3000);


3setInterval插入一個不斷循環的計時器事件.


setInterval(function () {
console.log("hello world");
},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模塊
var net = require("net");


//創建一個net.Server用來監聽
//這個API是創建一個新的TCP或IPC服務。
//當有連接請求 會調用這個匿名回調函數
var server = net.createServer((client_sock)=>{
	//收到客戶端接入的回調函數
	//client_spcl就是與客戶端通訊的socket
	console.log("client comming");
});


//指示監聽端口 為 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("start listening  ...");
});


//綁定建立鏈接事件 和客戶端不同
//這個會產生一個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("listener err");
});


//綁定關閉事件
server.on("close",function(){
	//服務器關閉 如果還有鏈接存在,直到所有連接關閉
	//這個事件才會被觸發
	console.log("server stop listener");

});



//停止偵聽 連接
//	server.unref();


//停止監聽 主動關閉socket
//參數 就是close事件的回調 可以寫在參數裏都可以
//他必須是在停止偵聽之後 調用
//如果不這樣的話  服務器 還是可以收到連接
//server.close();


Client客戶端

首先用ner.creatConnection或者net.connect創建連接到服務器

這時候你就要綁定connect的回調函數,一旦連接成功就會回調

close事件,socket關閉後觸發, data事件,收到數據就觸發

error事件,當socket有錯誤發生.

//引入net模塊
var net = require("net");


//鏈接服務器 一旦鏈接成功第二個參數
//就會立刻回調
var c_sock = net.connect({
	port:6800,
	host:"127.0.0.1",	
},()=>{
	console.log("connected to server!");

});


//這裏綁定connect事件 和上面那個效果相同
//上面那個是 被封裝成回調函數了
c_sock.on("connect",function(){
	console.log("connect success!");
	//socket.write(data,[,encoding][,callback])
	//在socket上發送數據,第二個參數指定字符串編碼默認UTF-8
	//如果發數據成功到內核的緩沖返回true,如果全部或部分
	//數據在用戶內中排隊,返回false,如果緩沖再次空閑則觸發
	//drain事件, 當數據最終寫出之後,調用callback回調.
	//第二個參數 和 第三個參數是可選的
	c_sock.write("hello socket server");

});



//綁定錯誤事件
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是十六進制 
var buf = 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的數據拷貝給新的
var buf2 = Buffer.from(buf);
console.log(buf2);
/////讀取其中的一個數據
//輸出的是123
console.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 
//這裏輸出的就是00 00 FF FF
//因為他是大尾法寫入,他的高位0000 低位FFFF
//大端法 大尾把高位放低地址作為起始地址
//所以輸出的就是 00 00 FF FF
console.log(buf);


讀取

//使用大尾讀出來 參數是從哪裏開始讀
var value = buf.readInt32BE(0);
console.log(value);






Buffer重要方法

1.Buffer.byteLength(str,encoding)返回字符對象

str可以說string,Buffer,Array,ArrayBuffer

對應的二進制長度.encoding如果是字符串,字符編碼模式utf-8

也就是存下str需要多長字節.

var len = Buffer.byteLength("HelloWorld");
//輸出10
console.log(len);
也可以是Buffer對象
var len = Buffer.byteLength(buf2);
//輸出5
console.log(buf2);




2.交換swap16,swap32,swap64 大尾小尾數據變化

16是兩個字節交換位置, 32是4個字節兩個兩個交換位置

64是前面4個和後面4個字節 交換位置

將buf解析為一個整數數組,並且以字節順序原地進行交換

//16個字節
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);

然後轉換成大尾

bufer.swap32();
//這裏輸出的就是0000 ffff 4個
//就是轉換成大端法,高位放地地址.
console.log(bufer);


3.buffer.values() 遍歷buf每個字節

for(var vlu of bufer.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")



如果未指定 offsetend,則填充整個 buf

這個簡化使得一個 Buffer 的創建與填充可以在一行內完成

例如填充ASCLL碼 'A'

bufer.fill('A');

console.log(bufer);






Node.js服務器開發(1)