IO.js UDP/Datagram

2018-11-28 22:36 更新

穩(wěn)定度: 2 - 穩(wěn)定

數(shù)據(jù)報(bào)socket通過require('dgram')使用。

重要提示:dgram.Socket#bind()的表現(xiàn)在v0.10中被改變,并且現(xiàn)在總是異步的,如果你有像這樣的代碼:

var s = dgram.createSocket('udp4');
s.bind(1234);
s.addMembership('224.0.0.114');

你必須改成這樣:

var s = dgram.createSocket('udp4');
s.bind(1234, function() {
  s.addMembership('224.0.0.114');
});

dgram.createSocket(type[, callback])

  • type String. 'udp4''udp6',兩者之一
  • callback Function. 可選,會(huì)被添加為message事件的監(jiān)聽器
  • Returns: socket對(duì)象

創(chuàng)建一個(gè)指定類型的數(shù)據(jù)報(bào)socket??捎妙愋褪莡dp4和udp6.

接受一個(gè)可選的回調(diào)函數(shù),它會(huì)被自動(dòng)添加為message事件的監(jiān)聽器。

如果你想要接收數(shù)據(jù)報(bào),調(diào)用socket.bind()。socket.bind()將會(huì)到所有網(wǎng)絡(luò)接口地址中的一個(gè)隨機(jī)端口(不論udp4和upd6 socket,它都可以正常工作)。你可以從socket.address().addresssocket.address().port中獲取地址和端口。

dgram.createSocket(options[, callback])

  • options Object
  • callback Function. 會(huì)被添加為message事件的監(jiān)聽器
  • Returns: socket對(duì)象

options對(duì)象必須包含一個(gè)type屬性,可是udp4或udp6。還有一個(gè)可選的reuseAddr布爾值屬性。

當(dāng)reuseAddrtrue時(shí),socket.bind()會(huì)重用地址,甚至是當(dāng)另一個(gè)進(jìn)程已經(jīng)在這之上綁定了一個(gè)socket時(shí)。默認(rèn)為false

接受一個(gè)可選的回調(diào)函數(shù),它會(huì)被自動(dòng)添加為message事件的監(jiān)聽器。

如果你想要接收數(shù)據(jù)報(bào),調(diào)用socket.bind()socket.bind()將會(huì)到所有網(wǎng)絡(luò)接口地址中的一個(gè)隨機(jī)端口(不論udp4和upd6 socket,它都可以正常工作)。你可以從socket.address().addresssocket.address().port中獲取地址和端口。

Class: dgram.Socket

dgram.Socket類封裝了數(shù)據(jù)報(bào)的功能。它必須被dgram.createSocket(...)創(chuàng)建。

Event: 'message'

  • msg Buffer object. 消息
  • rinfo Object. 遠(yuǎn)程地址信息

當(dāng)在socket中一個(gè)新的數(shù)據(jù)報(bào)可用時(shí)觸發(fā)。msg是一個(gè)buffer并且rinfo是一個(gè)包含發(fā)送者地址信息的對(duì)象:

socket.on('message', function(msg, rinfo) {
  console.log('Received %d bytes from %s:%d\n',
              msg.length, rinfo.address, rinfo.port);
});

Event: 'listening'

當(dāng)一個(gè)socket開始監(jiān)聽數(shù)據(jù)報(bào)時(shí)觸發(fā)。在UDP socket被創(chuàng)建時(shí)觸發(fā)。

Event: 'close'

在一個(gè)socket通過close()被關(guān)閉時(shí)觸發(fā)。這個(gè)socket中不會(huì)再觸發(fā)新的message事件。

Event: 'error'

  • exception Error object

當(dāng)錯(cuò)誤發(fā)生時(shí)觸發(fā)。

socket.send(buf, offset, length, port, address[, callback])

  • buf Buffer object or string. 要被發(fā)送的信息。
  • offset Integer. 信息在buffer里的初始偏移位置。
  • length Integer. 信息的字節(jié)數(shù)。
  • port Integer. 目標(biāo)端口。
  • address String. 目標(biāo)主機(jī)或IP地址。
  • callback Function. 可選,當(dāng)信息被發(fā)送后調(diào)用。

對(duì)于UDP socket,目標(biāo)端口和地址都必須被指定。address參數(shù)需要提供一個(gè)字符串,并且它會(huì)被DNS解析。

如果address被忽略,或者是一個(gè)空字符串。將會(huì)使用'0.0.0.0''::0'。這取決于網(wǎng)絡(luò)配置,這些默認(rèn)值 可能會(huì) 或 可能不會(huì) 正常工作;所以最好還是明確指定目標(biāo)地址。

如果一個(gè)socket先前沒有被調(diào)用bind來綁定,它將會(huì)賦于一個(gè)隨機(jī)端口數(shù)并且被綁定到“所有網(wǎng)絡(luò)接口”地址(udp4 socket'0.0.0.0',udp6則為'::0')。

一個(gè)可選的回調(diào)函數(shù)可以被指定,用來檢測(cè)DNS錯(cuò)誤,或決定重用buf對(duì)象是否安全。注意,DNS查找至少會(huì)延遲一個(gè)事件循環(huán)。唯一能確定數(shù)據(jù)報(bào)被發(fā)送的方法就是使用一個(gè)回調(diào)函數(shù)。

出于對(duì)多字節(jié)字符的考慮,offsetlength將會(huì)根據(jù)字節(jié)長度而不是字符位置被計(jì)算。

一個(gè)向localhost上的一個(gè)隨機(jī)端口發(fā)送UDP報(bào)文的例子:

var dgram = require('dgram');
var message = new Buffer("Some bytes");
var client = dgram.createSocket("udp4");
client.send(message, 0, message.length, 41234, "localhost", function(err) {
  client.close();
});
UDP數(shù)據(jù)報(bào)大小的注意事項(xiàng)

IPv4/v6數(shù)據(jù)報(bào)的最大大小取決于MTU(最大傳輸單位),和Payload Length字段大小。

  • Payload Length是16字節(jié)寬的,意味著一個(gè)正常的負(fù)載不能超過64K 八位字節(jié),包括網(wǎng)絡(luò)頭和數(shù)據(jù)(65,507 字節(jié) = 65,535 ? 8 字節(jié) UDP 頭 ? 20 字節(jié) IP 頭);對(duì)于環(huán)回接口總是true,但是如此大的數(shù)據(jù)報(bào)對(duì)于大多數(shù)主機(jī)和網(wǎng)絡(luò)來說都是不現(xiàn)實(shí)的。

  • MTU是指定的鏈路層技術(shù)支持的報(bào)文的最大大小。對(duì)于所有連接,IPv4允許最小MTU為68八位字節(jié),而推薦的IPv4 MTU是576(通常作為撥號(hào)類應(yīng)用的推薦MTU),無論它們是完整的還是以碎片形式到達(dá)。

  • 對(duì)于IPv6,最小MTU是1280八位字節(jié),但是,允許的最小buffer重組大小是1500八位字節(jié)。68八位字節(jié)非常小,所以大多數(shù)的當(dāng)前鏈路層技術(shù)的最小MTU都是1500(如Ethernet)。

注意,不可能提前知道一個(gè)報(bào)文可能經(jīng)過的每一個(gè)連接MTU,并且通常不能發(fā)送一個(gè)大于(接收者)MTU的數(shù)據(jù)報(bào)(報(bào)文會(huì)被默默丟棄,不會(huì)通知源頭:這個(gè)數(shù)據(jù)沒有到達(dá)已定的接收方)。

socket.bind(port[, address][, callback])

  • port Integer
  • address String, 可選
  • callback Function 可選,沒有參數(shù)。當(dāng)綁定完畢后觸發(fā)。

對(duì)于UDP socket,監(jiān)聽一個(gè)具名的端口和一個(gè)可選的地址上的數(shù)據(jù)報(bào)。如果address沒有被指定,操作系統(tǒng)將會(huì)試圖監(jiān)聽所有端口。在綁定完畢后,listening事件會(huì)被吃法,并且回調(diào)函數(shù)(如果指定了)會(huì)被調(diào)用。同時(shí)指定listening事件的監(jiān)聽器和callback沒有危險(xiǎn),但是不是很有用。

一個(gè)綁定的數(shù)據(jù)報(bào)socket將會(huì)保持io.js進(jìn)程的運(yùn)行,來接受數(shù)據(jù)報(bào)。

如果綁定失敗,一個(gè)error事件會(huì)產(chǎn)生。極少數(shù)情況下(例如綁定一個(gè)關(guān)閉的socket),這個(gè)方法會(huì)拋出一個(gè)錯(cuò)誤。

一個(gè)監(jiān)聽41234端口的UDP服務(wù)器:

var dgram = require("dgram");

var server = dgram.createSocket("udp4");

server.on("error", function (err) {
  console.log("server error:\n" + err.stack);
  server.close();
});

server.on("message", function (msg, rinfo) {
  console.log("server got: " + msg + " from " +
    rinfo.address + ":" + rinfo.port);
});

server.on("listening", function () {
  var address = server.address();
  console.log("server listening " +
      address.address + ":" + address.port);
});

server.bind(41234);
// server listening 0.0.0.0:41234

socket.bind(options[, callback])

  • options Object - 必選,支持以下屬性:

  • port Number - 必須
  • address String - 可選
  • exclusive Boolean - 可選

  • callback Function - 可選

optionsprotaddress屬性,以及可選的回調(diào)函數(shù),與socket.bind(port, [address], [callback])中它們的表現(xiàn)一致。

exclusivefalse(默認(rèn)),那么集群的工作進(jìn)程將會(huì)使用相同的底層句柄,允許共享處理連接的職責(zé)。當(dāng)為true時(shí),句柄不被共享,企圖共享端口會(huì)導(dǎo)致一個(gè)錯(cuò)誤。一個(gè)監(jiān)聽一個(gè)exclusive端口的例子:

socket.bind({
  address: 'localhost',
  port: 8000,
  exclusive: true
});

socket.close([callback])

關(guān)閉底層socket,并且停止監(jiān)聽新數(shù)據(jù)。如果提供了回調(diào)函數(shù),它會(huì)被添加為close事件的監(jiān)聽器。

socket.address()

返回一個(gè)包含socket地址信息的對(duì)象。對(duì)于UDP socket,這個(gè)對(duì)象將會(huì)包含addressfamilyport。

socket.setBroadcast(flag)

  • flag Boolean

設(shè)置或清除SO_BROADCAST``socket設(shè)置。當(dāng)這個(gè)選項(xiàng)被設(shè)置,UDP報(bào)文將會(huì)被送至本地接口的廣播地址。

socket.setTTL(ttl)

  • ttl Integer

設(shè)置IP_TTL``socket選項(xiàng)。TTL的意思是“生存時(shí)間(Time to Live)”,但是在這里的上下文中,它值一個(gè)報(bào)文通過的IP躍點(diǎn)數(shù)。每轉(zhuǎn)發(fā)報(bào)文的路由或網(wǎng)關(guān)都會(huì)遞減TTL。如果TTL被一個(gè)路由遞減為0,它將不再被轉(zhuǎn)發(fā)。改變TTL值常用于網(wǎng)絡(luò)探測(cè)器或多播。

setTTL()的參數(shù)是一個(gè)1225之間的躍點(diǎn)數(shù)。多數(shù)系統(tǒng)中的默認(rèn)值為64

socket.setMulticastTTL(ttl)

  • ttl Integer

設(shè)置IP_MULTICAST_TTL``socket選項(xiàng)。TTL的意思是“生存時(shí)間(Time to Live)”,但是在這里的上下文中,它值一個(gè)報(bào)文通過的IP躍點(diǎn)數(shù),特別是組播流量。每轉(zhuǎn)發(fā)報(bào)文的路由或網(wǎng)關(guān)都會(huì)遞減TTL。如果TTL被一個(gè)路由遞減為0,它將不再被轉(zhuǎn)發(fā)。

setMulticastTTL()的參數(shù)是一個(gè)0225之間的躍點(diǎn)數(shù)。多數(shù)系統(tǒng)中的默認(rèn)值為1。

socket.setMulticastLoopback(flag)

  • flag Boolean

設(shè)置或清除IP_MULTICAST_LOOP``socket選項(xiàng)。當(dāng)這個(gè)選項(xiàng)被設(shè)置,組播報(bào)文也將會(huì)在本地接口上接收。

socket.addMembership(multicastAddress[, multicastInterface])

  • multicastAddress String
  • multicastInterface String, 可選

告訴內(nèi)核加入一個(gè)組播分組,通過IP_ADD_MEMBERSHIP``socket選項(xiàng)。

如果multicastInterface沒有被指定,那么操作系統(tǒng)將會(huì)嘗試加入成為所有可用的接口的成員。

socket.dropMembership(multicastAddress[, multicastInterface])

  • multicastAddress String
  • multicastInterface String, 可選

addMembership相反 - 告訴內(nèi)核離開一個(gè)組播分組,通過IP_DROP_MEMBERSHIP``socket選項(xiàng)。當(dāng)socket被關(guān)閉或進(jìn)程結(jié)束時(shí),它會(huì)被內(nèi)核自動(dòng)調(diào)用。所以大多數(shù)應(yīng)用不需要親自調(diào)用它。

如果multicastInterface沒有被指定,那么操作系統(tǒng)將會(huì)嘗試脫離所有可用的接口。

socket.unref()

在一個(gè)socket上調(diào)用unref將會(huì)在它是事件系統(tǒng)中唯一活躍的socket時(shí),允許程序退出。如果socket已經(jīng)被unref,再次調(diào)用將不會(huì)有任何效果。

返回一個(gè)socket

socket.ref()

unref相反,在一個(gè)先前被unrefsocket上調(diào)用ref,那么在它是唯一的剩余的socket(默認(rèn)行為)時(shí),將不允許程序退出。如果socket已經(jīng)被ref,再次調(diào)用將不會(huì)有任何效果。

返回一個(gè)socket。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)