NIO UDP 编程

编程技术  /  houtizong 发布于 3年前   105
   和TCP的SocketChannel类似,UDP的DatagramChannel能充分利用NIO的优势。

服务端:Selector, DatagramChannel, ByteBuffer

客户端:DatagramChannel, ByteBuffer

区别:
a. 服务端没有与TCP的ServerSocketChannel相对应的Channel,服务端和客户端之间更趋于平等,不过服务端的端口号还是固定的。

b. Selector在处理完读取操作后,会触发写操作:发送数据到客户端。

1. 服务端
public class UDPEchoServerSelector {private static final int TIMEOUT = 4000; // 超时 (毫秒)private static final int CAPACITY = 255;public static void main(String[] args) throws IOException {args = new String[1];args[0] = "4451";int servPort = Integer.parseInt(args[0]);Selector sel = Selector.open(); // 创建选择器,可以处理多路通道。DatagramChannel channel = DatagramChannel.open();channel.configureBlocking(false);channel.socket().bind(new InetSocketAddress(servPort)); // 通道关联的socket绑定地址channel.register(sel, SelectionKey.OP_READ, new ClientData());while (true) { // 持续运行,接收和返回数据if (sel.select(TIMEOUT) == 0) {System.out.println("No I/O needs to be processed");continue;}Iterator<SelectionKey> iter = sel.selectedKeys().iterator(); // 获取可操作的选择键集合while (iter.hasNext()) {SelectionKey key = iter.next(); // 键为位掩码if (key.isReadable()) { // 客户端有数据发送过来handleRead(key);}if (key.isValid() && key.isWritable()) { // 通道正常,且客户端需要响应handleWrite(key);}iter.remove(); // 从集合中移除选择键}}}private static void handleRead(SelectionKey key) throws IOException {DatagramChannel channel = (DatagramChannel) key.channel();ClientData clntDat = (ClientData) key.attachment();clntDat.buffer.clear();clntDat.clientAddress = channel.receive(clntDat.buffer); // 获取客户端的地址,用以发送响应if (clntDat.clientAddress != null) { // 接收到数据key.interestOps(SelectionKey.OP_WRITE); // 关注客户端读取响应}}private static void handleWrite(SelectionKey key) throws IOException {DatagramChannel channel = (DatagramChannel) key.channel();ClientData clntDat = (ClientData) key.attachment();clntDat.buffer.flip(); // 从起始位置开始发送int bytesSent = channel.send(clntDat.buffer, clntDat.clientAddress);if (bytesSent != 0) {key.interestOps(SelectionKey.OP_READ); // 关注客户端发送数据}}public static class ClientData {public SocketAddress clientAddress;public ByteBuffer buffer = ByteBuffer.allocate(CAPACITY);}}



2. 客户端
public class UDPEchoClient {private static final int CAPACITY = 255;private static final String UTF8 = "UTF-8";public static void main(String[] args) throws IOException {args = new String[2];args[0] = "localhost";args[1] = "4451";String servName = args[0];int servPort = Integer.parseInt(args[1]);DatagramChannel clntChan = DatagramChannel.open();clntChan.configureBlocking(false);clntChan.connect(new InetSocketAddress(servName, servPort));ByteBuffer sentBuffer = ByteBuffer.wrap("Hello UDP".getBytes(UTF8));int bytesSent = clntChan.write(sentBuffer); // 向服务器发送数据System.out.println("UDP client sent " + bytesSent + " bytes");ByteBuffer recvBuffer = ByteBuffer.allocate(CAPACITY);clntChan.receive(recvBuffer); // 读取响应recvBuffer.flip();System.out.println("UDP client received: " + new String(recvBuffer.array(), UTF8));}}



客户端连接服务器后,发送数据可以用write或send方法:
...clntChan.connect(new InetSocketAddress(servName, servPort));...int bytesSent = clntChan.write(sentBuffer);


...clntChan.connect(new InetSocketAddress(servName, servPort));...int bytesSent = clntChan.send(sentBuffer, new InetSocketAddress(servName, servPort)); // 发送地址必须和前面的连接地址相同,否则报java.lang.IllegalArgumentException: Connected address not equal to target address


客户端没有连接服务器,需要用send方法指定目标地址:
...int bytesSent = clntChan.send(sentBuffer, new InetSocketAddress(servName, servPort)); // 使用write方法会报java.nio.channels.NotYetConnectedException
上一篇:MySQL 触发器
下一篇:JVM 四种引用

请勿发布不友善或者负能量的内容。与人为善,比聪明更重要!

留言需要登陆哦

技术博客集 - 网站简介:
前后端技术:
后端基于Hyperf2.1框架开发,前端使用Bootstrap可视化布局系统生成

网站主要作用:
1.编程技术分享及讨论交流,内置聊天系统;
2.测试交流框架问题,比如:Hyperf、Laravel、TP、beego;
3.本站数据是基于大数据采集等爬虫技术为基础助力分享知识,如有侵权请发邮件到站长邮箱,站长会尽快处理;
4.站长邮箱:[email protected];

      订阅博客周刊 去订阅

文章归档

文章标签

友情链接

Auther ·HouTiZong
侯体宗的博客
© 2020 zongscan.com
版权所有ICP证 : 粤ICP备20027696号
PHP交流群 也可以扫右边的二维码
侯体宗的博客