標籤: nodejs udp tcp bufferjavascript
1byte表明的是一個字節,是
文件存儲
的最小單位。在基本文件單位中,咱們有如下的等價關係。 1M = 1024 K,1k = 1024 byte。html1bit表明則是一個Binary digit(二進制數位)。說人話,就是1010101中的一個1或者0。前端
在TCP/UDP協議
中,比較普遍的定義是1 byte = 8 bit,這個定義不是嚴格的。換句話說,你能夠選擇不遵照。java
在計算機網絡的七層協議中,這兩個是傳輸層的協議,咱們經常使用的HTTP協議屬於一種特殊的TCP鏈接。通常狀況下,咱們將TCP鏈接經過IP做爲地址關聯,經過握手的方式鏈接,因此TCP協議又被稱爲是TCP/IP協議。udp協議則是一種更爲暴力的協議,通常沒有握手的過程,咱們常常會把它用在DNS的查詢上面。node
區別 | udp | tcp |
---|---|---|
鏈接性 | 面向非鏈接 | 面向鏈接 |
傳輸可靠性 | 不可靠 | 可靠 |
應用場景 | 少許數據 | 傳輸大量數據 |
速度 | 快 | 慢 |
好了,咱們先複習到這裏。若是還有不知道的,請QQ大家的計算機網絡老師。c++
對於tcp/HTTP協議的場景,你們其實都是比較熟悉的,成熟的框架你們都是用的六六的,因此這裏就再也不贅述,下文將着重於表達UDP協議。git
嗯,咱們先來看一下一個簡單的udp的例子。後端
// server.js const dgram = require('dgram'); const server = dgram.createSocket('udp4'); server.on('error', (err) => { console.log(`server error:\n${err.stack}`); server.close(); }); server.on('message', (msg, rinfo) => { console.log(`server got: ${msg} from ${rinfo.address}:${rinfo.port}`); }); server.on('listening', () => { var address = server.address(); console.log(`server listening ${address.address}:${address.port}`); }); server.bind(41234,()=>{ console.log('server bind success'); }); // server listening 0.0.0.0:41234 //client.js const dgram = require('dgram'); const message = Buffer.from('Some bytes'); const client = dgram.createSocket('udp4'); client.send(message, 41234, 'localhost', (err) => { client.close(); });
代碼仍是很簡單的。使用到的庫是dgram
這個庫是node自帶的,直接require就ok,有關的事件以下:api
error 當發生錯誤的時候會觸發這個事件。瀏覽器
message 當收到了udp請求的時候將會被觸發。
listening 當接口被綁定以後,若是綁定承購,開始監聽的時候,將會觸發該事件。
close 當udp請求被關閉的時候,將會觸發該事件。
經常使用的方法函數,以下:
createSocket 建立實例,這裏可以建立的類型是udp4/udp6,分別對應的是ipv4/ipv6
bind 綁定指定的接口
send 發出指定的message。這裏有個坑,message的類型只支持 Buffer|String|Array
具體的函數介紹和使用說明,請參閱官方文檔。對於一個簡單udp協議,使用的時候,咱們通常將會把監聽和請求合併封裝在一塊兒,做爲一個統一服務。
var dgram = require('dgram'); var server = dgram.createSocket('udp4') var port = 0; var targetPort = 123; var targetIp = 10.10.10.10;//這裏也能夠支持用域名,它會本身作dns解析 function sendAndRecv(targetPort,targetIp,desPort,message,callback){ server.bind(port,()=>{ var _message = Buffer.from(message); server.send(_message,targetPort,targetIp,(err)={ if(!err){ server.on('message',(msg,info)=>{ console.log(`server got: ${msg.toString()} from ${info.address}:${info.port}`); callback&&callback(message.toString()); //這裏要注意哦,msg的類型是Buffer哦! }) } }) }) }
後端的同窗使用的語言是c/c++對於他們來講,實現一個和協議一毛同樣的東西是比較好理解的,畢竟,當年定義協議的人,也是寫這個的嘛。可是,對於咱們前端而言,咱們可以依賴的就只有咱們的node了。node的運行是基於v8的,因此,本質上來講,node並不具有有直接內存操做能力,因此,爲了操做各類bit位,咱們須要引入一個新的變量類型Buffer,這個類型是node獨有的,在瀏覽器內核中,與之最接近的是ArrayBuffer,在用來處理音視頻流的在WEBRTC中咱們常常能用的到它。
js嘛,仍是比較簡單的。咱們直接看代碼吧。
//實例化 var buf = new Buffer(); //寫 buf.write("XXXXX"); //讀 buf.readInt8();
具體的類型說明和函數使用,請參考官方文檔。
咱們這裏着重說一下踩過的坑。在buffer對象中,使用的是byte記位。也就是說,對於以下:
var buf = new Buffer(1);// 1 byte == 8bit 能夠寫入 0x00 = 0000 0000 buf.writeInt8(0x00); //對於16進制的不一樣位數,能夠參考以下函數: //不一樣的長度,在寫入的時候,要使用不一樣的函數,具體須要使用到的函數請參考,上文給出的官方文檔。 function getBuffer(value, length) { var buffer = length && new Buffer(length); switch (length) { case 1: buffer.writeUInt8(value); return buffer; case 2: buffer.writeInt16BE(value); return buffer; case 4: buffer.writeFloatBE(value); return buffer; default: return new Buffer(value); } }
這裏順帶加一個函數,如何把十進制的ip string轉換成整型數據的js實現。
function ip2Int(IP) { var REG = /^(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])\.(\d{1,2}|1\d\d|2[0-4]\d|25[0-5])$/; var xH = "", result = REG.exec(IP); if (!result) return false; return (parseInt(result[1]) << 24 | parseInt(result[2]) << 16 | parseInt(result[3]) << 8 | parseInt(result[4])); } ip2Int("10.10.10.10");//168430090