数据报SOCKET(UDP)
用Vert.x中的用户数据报文协议是很好的。UDP是无连接传输这基本意味着你不必保存远程端点的连接。相反可以接收或发送数据包,而远程地址包含在数据包中。除了UDP使用没有TCP一样安全,这就是说,采用UDP发送数据不保证发出的数据报文一定会被收到。仅有的保证是要么完整收到要么没收到。也就是说不能发送超过网卡MTU大小的数据,这是因为每个数据报将被作为一个包发送。必须注意甚至小于MTU的包也有可能失败。什么大小的包会失败取决于操作系统等因素,所以首要准则是发送小报文。由于UDP具有的特性,它很适合发送允许丢包的应用(如应用监控的例子)。好处是它与TCP比较,省了很多开销,UDP可用NetServer和NetClient进行处理。
创建一个DatagramSocket
为了使用UDP,首先需要创建DatagramSocket。然后就可以发送数据和接收数据了
DatagramSocket socket =vertx.createDatagramSocket(new DatagramSocketOptions());
DatagramSocket不必绑定了特定端口。这样象客户端一样发送数据没有问题,更多的内容在下一节讨论.
发送数据包
如前所述,UDP用包来发送数据到远端,但是不需以长连接的方式。这就意示着不同的包可以发送到不同的远程端点。发送包可以象下面显示的一样简单:
DatagramSocket socket =vertx.createDatagramSocket(new DatagramSocketOptions());
Buffer buffer =Buffer.buffer("content");
// Send a Buffer
socket.send(buffer, 1234, "10.0.0.1",asyncResult -> {
System.out.println("Send succeeded? " +asyncResult.succeeded());
});
// Send a String
socket.send("A string used ascontent", 1234, "10.0.0.1", asyncResult -> {
System.out.println("Send succeeded? " +asyncResult.succeeded());
});
接收数据报
为了接收数据包,通过listen(…)方法绑定到DatagramSocket。这样将从绑定的地址和端口接数据包了(DatagramPacket)。除此,也需要为DatagramSocket设置一个在接收到数据时调用的处理器。
DatagramPacket有以下方法:
· sender:是一个代表发送数据包的地址(InetSocketAddress)
· data:承载接收数据的缓冲器(Buffer)
为了在指定的地址和端口侦听,可以象下面显示这样做:
DatagramSocket socket = vertx.createDatagramSocket(newDatagramSocketOptions());
socket.listen(1234, "0.0.0.0",asyncResult -> {
if(asyncResult.succeeded()) {
socket.handler(packet -> {
//Do something with the packet
});
} else{
System.out.println("Listen failed" + asyncResult.cause());
}
});
甚至代码 AsyncResult标识是成功的,这仅表示可以在网络堆栈上被写入,而不能保证数据一定到达或将会到达远程端点。如是需要可靠的传输,可以在传送数据之前使用TCP握手逻辑。
多播
发送多播包
多播是允许多个Socket接收同样的数据包。通过将socket加入到多播组,然后向多播组发送数据。让我们看一下怎样加入多播组,接收数据将在下一节讨论。现在让我们关注怎样发送数据。发送多播包与发送正常的数据报包没有什么不同,只是在向send方法传递的是多播组参数。如下所示:
DatagramSocket socket =vertx.createDatagramSocket(new DatagramSocketOptions());
Buffer buffer =Buffer.buffer("content");
// Send a Buffer to a multicast address
socket.send(buffer, 1234,"230.0.0.1", asyncResult -> {
System.out.println("Send succeeded? " +asyncResult.succeeded());
});
所有Socket都加入多播组230.0.0.1,并将接收数据。
接收多播包
如果需要要接收数据包,只需要用listen(…)方法将DatagramSocket绑定的特定的多播组并加入多播组。这样将会从接收到来自DatagramSocket侦听的地址和端口发送来的DatagramPacket,同时也可以发送DatagramPacket到多播组。也可以在接到DatagraPacket时调用设置的处理器。
DatagramPacket有以下方法:
· sender():代表包发送者的地址(InetSocketAddress)
· data():承载接收数据的缓冲器(Buffer)
侦听指定的端口和地址,并且从多播组230.0.0.1上接收数据,可以象下面这样做:
DatagramSocket socket =vertx.createDatagramSocket(new DatagramSocketOptions());
socket.listen(1234, "0.0.0.0",asyncResult -> {
if(asyncResult.succeeded()) {
socket.handler(packet -> {
//Do something with the packet
});
//join the multicast group
socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> {
System.out.println("Listen succeeded? " + asyncResult2.succeeded());
});
} else{
System.out.println("Listen failed" + asyncResult.cause());
}
});
解除侦听/离开多播组
有一些情况下需要在限定的时间内从多播组中接收数据。在此情 况下,首先得开始侦听,稍后解侦听。下面是代码:
DatagramSocket socket =vertx.createDatagramSocket(new DatagramSocketOptions());
socket.listen(1234, "0.0.0.0",asyncResult -> {
if(asyncResult.succeeded()) {
socket.handler(packet -> {
// Do something with the packet
});
//join the multicast group
socket.listenMulticastGroup("230.0.0.1", asyncResult2 -> {
if (asyncResult2.succeeded()) {
// will now receive packets for group
// do some work
socket.unlistenMulticastGroup("230.0.0.1", asyncResult3 ->{
System.out.println("Unlisten succeeded? " +asyncResult3.succeeded());
});
} else {
System.out.println("Listen failed" + asyncResult2.cause());
}
});
}else {
System.out.println("Listen failed" + asyncResult.cause());
}
});
阻塞式多播
除了解除一个多播地址外,阻塞特定的发送地址也是可行的。要小心这仅可以工作在某些操作系统和内核版本。因此请检查操作系统文档确定其是否支持,这是一个高手特性。多指定的地址阻塞多播,可以在DatagramSocket调用blockMulticastGroup(..)方法,如下所示:
DatagramSocket socket =vertx.createDatagramSocket(new DatagramSocketOptions());
// Some code
// This would block packets which are send from10.0.0.2
socket.blockMulticastGroup("230.0.0.1","10.0.0.2", asyncResult -> {
System.out.println("block succeeded? " +asyncResult.succeeded());
});
DagatramSocket属性
在创建一个DatagramSocket时,通过DatagramSocketOption对象设置多个属性可以改变DatagramSocket的行为。这此属性如下:
· setSendBufferSize设置发送缓冲器字节大小。
· setReceiveBufferSize设置TCP接收缓冲器字节大小。
· setResueAddress如果为true,在socket被关闭后,TIME_WAIT状态下的地址可重用。
· setTrafficClass
· setBroadcast设置或清除SO_BROADCAST socket选项。设置此选项时,UDP包可以被发送到本地网卡的广播地址。
· setMulticastNetworkInterface设置或清除IP_MULTICAST_LOOP socket选项。设置此选项,多播包可以在本地网卡上被接收。
· setMulticastTimeToLive设置IP_MULTICAST_TTL socket选项。TTL代表“Timeto Live,”,但是在此上下文,TTL指的是包允许通过网络的跳数,特别是在多播传输时。每一个路由器或网关在传输包时会减省TTL。如果TTL被路由器减少到0时,包将不会被路由。
DatagramSocket本地地址
通过调用localAddress方法,你可以发现Socket的本地地址(如UDP Socket这侧的地址)。如果你用listen(…)进行DatagramSocket进行绑定,你将得到一个InetSocketAddress实例,如果在调用listen(…)之前调用localAddress方法,你会得到null值。
关闭DatagramSocket
可以调用close方法关闭socket,这将关闭socket并释放资源。