我本以为NIO已经差不多了,可谁想到… 今天在看upd的时候,惊人的发现了这个东西:DatagramChannel。嗯? channel?NIO? 对,没错。还真的有一个udp用的channel! 我本身对这个东西是心有疑惑的,udp他本身就是一个异步性很强的东西,为什么还需要NIO呢? 我自己暂时想不出个所以然来,但是本着一家人就要阵阵齐齐的心态,还是先整理为好,万一哪天用上了呢?
DatagramChannel
首先,他是一个SelectableChannel,这也就意味着他可以和selector一起使用。具体和selector结合使用就不多说了,因为和其他的channel用起来差不多。
打开
也是和其他的Channel很像,没有共有的构造函数,要使用静态方法来获得实例:
1 | DatagramChannel channel = DatagramChannel.open(); |
接下来的操作也是十分熟悉:获得与channel关联的socket,将其与一个socketAddress绑定。同时和其他channel一样,在java 7之后channel可以直接绑定address。
1 | DatagramSocket socket = channel.socket(); |
接收数据
这里开始就和原来的channel有点不一样了,但是感觉又像DatagramSocket。可以使用receive()方法来接收数据,同时receive方法返回一个SocketAddress来表示数据发送方的地址。因为是channel,理所当然的应该使用bytebuffer来作为数据的载体。
1 | public SocketAddress receive(Bytebuffer dst) throws IOException |
如果channel是阻塞的(默认状态),这个方法在获取到数据包之前不会返回;如果channel是非阻塞的,没有包读取的情况下,会直接返回null。
发送数据
send方法可以将一个数据包从bytebuffer 写入 channel:
1 | public int send(Bytebuffer src, SocketAddress target) throws IOException |
这个方法返回写入的字节数,第一个方法传入buffer,第二个方法传入目标地址。不过要记住,如果需要将buffer多次发送给不同的目标,不要忘记将buffer“倒带” rewind()
连接
这个连接就有一个很大的误区了。。。并非字面意思上的连接,而是和DatagramSocket的那个connect差不多。只是名字叫连接,并没有实际的建立连接,连接之后,channel只接受与之连接的地址 发送的数据包 同时也只像那个地址发送数据包。同时还有2个方法来检测channel是否连接/控制channel“断开”连接。但是他其实并不会断开连接,因为connect方法本身就没有建立连接…使用了这个方法后,channel会被允许再次向任何地址 接受/发送数据包
1 | InetSocketAddress remoteAddress = new InetSocketAddress(remoteHostName,port); |
其实乍一看这个方法并没有什么用,我也真的是这样认为的..不过在后面就会发现2个熟悉的东西,并且只有在connect之后才能只用。
read/write
说到channel怎么能少了这两个方法呢??这两位才是读写操作的先祖啊。 之前说的receive 以及 send 是用于特殊用途的读写方法,所以channel当然可以用这些基本的方法,但是有一个条件,那就是上面提到的connect。read 和 write 方法仅能在已 connect的channel上使用:
1 | public abstract int read(ByteBuffer dst) |
关闭
有开就有关,总体来说差不多,可以通过调用close来关闭channel,但是还是用try-with-recources比较好
1 | public void close() throws IOException |