数据报(UDP)信道
http://book.51cto.com/art/200902/109761.htm
摘要:《Java TCP/IP Socket编程》第5章NIO,本章将对"New I/O"工具包的主要应用进行介绍。NIO主要包括两个部分:java.nio.channels包介绍了Selector和Channel抽象,java.nio包介绍了Buffer抽象。本节为大家介绍数据报(UDP)信道。
标签:UDP Java TCP IP Socket 编程
Java的NIO包通过DatagramChannel类实现了数据报(UDP)信道。与我们之前看到的其他形式的SelectableChannel一样,DatagramChannel在DatagramSocket上添加了选择和非阻塞行为,以及基于缓冲区的I/O操作能力。
DatagramChannel: 创建,连接和关闭
static DatagramChannel open() boolean isOpen() DatagramSocket socket() void close()
|
需要调用DatagramChannel的open()工厂方法来创建一个DatagramChannel实例,该实例是未绑定的。DatagramChannel只是对基本DatagramSocket的一个包装器(wrapper)。使用其socket()方法可以直接访问内部的DatagramSocket实例。这就允许通过调用基本的DatagramSocket方法进行绑定、设置套接字选项等操作。用完DatagramChannel后,要调用它的close()方法将其关闭。
只要创建了一个DatagramChannel实例,就可以非常直接地发送和接收数据。
DatagramChannel: 发送和接收
int send(ByteBuffer src, SocketAddress target) SocketAddress receive(ByteBuffer dst)
|
send()方法用于创建一个包含了给定ByteBuffer中的数据的数据报文,并将其发送到目的地址指定的SocketAddress上。receive()方法用于将接收到的数据报文存入指定缓冲区并返回发送者的地址。重要提示:如果缓冲区的剩余空间小于数据报文中的数据大小,多余的数据将毫无提示地丢弃。
以下代码段用于创建一个DatagramChannel实例,并将UTF-16编码的字符串"Hello"发送到运行在同一主机的5000端口上的UDP服务器上。
DatagramChannel channel = DatagramChannel.open(); ByteBuffer buffer = ByteBuffer.wrap("Hello".getBytes("UTF-16")); channel.send(buffer, new InetSocketAddress("localhost", 5000));
|
以下代码段用于创建一个DatagramChannel实例,将底层的套接字绑定到5000端口,接收最长为20字节的数据报文,并将字节转换成使用UTF-16编码的字符串。
DatagramChannel channel = DatagramChannel.open(); channel.socket().bind(new InetSocketAddress(5000)); ByteBuffer buffer = ByteBuffer.allocateDirect(20); SocketAddress address = channel.receive(buffer); buffer.flip(); String received = Charset.forName("UTF-16"). newDecoder().decode(buffer).toString();
|
在上面的send()实例中,调用send()方法时并没有显式地绑定本地端口,因此将随机选择一个可用端口。相应的receive()方法用于返回一个SocketAddress,其中包含了端口号。
如果总是向同一个远程终端发送或接收数据,我们可以选择调用connect()方法,并使用 SocketAddress指定远程终端的地址。
DatagramChannel: 连接DatagramChannel
DatagramChannel connect(SocketAddress remote) DatagramChannel disconnect() boolean isConnected() int read(ByteBuffer dst) long read(ByteBuffer[] dsts) long read(ByteBuffer[] dsts, int offset, int length) int write(ByteBuffer src) long write(ByteBuffer[] srcs) long write(ByteBuffer[] srcs, int offset, int length)
|
这些方法限制我们只能通过指定的地址发送和接收数据。为什么要这样做呢?原因之一是调用connect()方法后,可以使用read()和write()方法来代替receive()和send()方法,并且不需要处理远程地址。read()和write()方法分别用于接收和发送一个数据报文。分散式读操作以一个ByteBuffer数组为参数,只接收一个数据报文,并按顺序将其填入缓冲区中。聚集式写操作将缓冲区数组中的所有字节连接起来创建一个要传输的数据报文。重要提示:现在能够发送的最大数据报文可以包含65507个字节,试图发送更多的数据将被无提示地截断。
使用connect()方法的另一个好处是,已建立连接的数据报文信道可能只接收从指定终端发送来的数据,因此我们不需要测试接收端的有效性。注意,DatagramChannel的connect()方法只起到限制发送和接收终端的作用,连接时并没有数据包在SocketChannel上进行交换,而且也不需要像SocketChannel那样等待或测试连接是否完成。(见第6章)
到目前为止DatagramChannel看起来与DatagramSocket非常相似。数据报文信道和套接字的主要区别是,信道可以进行非阻塞I/O操作和使用选择器。DatagramChannel中选择器的创建,信道的注册、选择等,与SocketChannel几乎一模一样。有一个区别是DatagramChannel不能注册连接I/O操作,不过也不需要这样做,因为DatagramChannel的connect()方法永远不会阻塞。
DatagramChannel: 设置阻塞行为和使用选择器
SelectableChannel configureBlocking(boolean block) boolean isBlocking() SelectionKey register(Selector sel, int ops) SelectionKey register(Selector sel, int ops, Object attachment) boolean isRegistered() int validOps() SelectionKey keyFor(Selector sel)
|
这些方法的功能与SocketChannel和ServerSocketChannel中的相应方法一样。
下面使用DatagramChannel对第4章中的DatagramSocket UDP回显服务器进行重写。服务器侦听指定的端口,并将接收到的数据报文简单地回发给客户端。重写后的服务器与原来版本的主要区别是它不会在send()和receive()方法上阻塞等待。
UDPEchoServerSelector.java
0 import java.io.IOException; 1 import java.net.InetSocketAddress; 2 import java.net.SocketAddress; 3 import java.nio.ByteBuffer; 4 import java.nio.channels.DatagramChannel; 5 import java.nio.channels.SelectionKey; 6 import java.nio.channels.Selector; 7 import java.util.Iterator; 8 9 public class UDPEchoServerSelector { 10 11 private static final int TIMEOUT = 3000; // Wait timeout (milliseconds) 12 13 private static final int ECHOMAX = 255; // Maximum size of echo datagram 14 15 public static void main(String[] args) throws IOException { 16 17 if (args.length != 1) // Test for correct argument list 18 throw new IllegalArgumentException("Parameter(s): <Port>"); 19 20 int servPort = Integer.parseInt(args[0]); 21 22 // Create a selector to multiplex client connections. 23 Selector selector = Selector.open(); 24 25 DatagramChannel channel = DatagramChannel.open(); 26 channel.configureBlocking(false); 27 channel.socket().bind(new InetSocketAddress(servPort)); 28 channel.register(selector, SelectionKey.OP_READ, new ClientRecord()); 29 30 while (true) { // Run forever, receiving and echoing datagrams 31 // Wait for task or until timeout expires 32 if (selector.select(TIMEOUT) == 0) { 33 System.out.print("."); 34 continue; 35 } 36 37 // Get iterator on set of keys with I/O to process 38 Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator(); 39 while (keyIter.hasNext()) { 40 SelectionKey key = keyIter.next(); // Key is bit mask 41 42 // Client socket channel has pending data? 43 if (key.isReadable()) 44 handleRead(key); 45 46 // Client socket channel is available for writing and 47 // key is valid (i.e., channel not closed). 48 if (key.isValid() && key.isWritable()) 49 handleWrite(key); 50 51 keyIter.remove(); 52 } 53 } 54 } 55 56 public static void handleRead(SelectionKey key) throws IOException { 57 DatagramChannel channel = (DatagramChannel) key.channel(); 58 ClientRecord clntRec = (ClientRecord) key.attachment(); 59 clntRec.buffer.clear(); // Prepare buffer for receiving 60 clntRec.clientAddress = channel.receive(clntRec.buffer); 61 if (clntRec.clientAddress != null) { // Did we receive something? 62 // Register write with the selector 63 key.interestOps(SelectionKey.OP_WRITE); 64 } 65 } 66 67 public static void handleWrite(SelectionKey key) throws IOException { 68 DatagramChannel channel = (DatagramChannel) key.channel(); 69 ClientRecord clntRec = (ClientRecord) key.attachment(); 70 clntRec.buffer.flip(); // Prepare buffer for sending 71 int bytesSent = channel.send(clntRec.buffer, clntRec.clientAddress); 72 if (bytesSent != 0) { // Buffer completely written? 73 // No longer interested in writes 74 key.interestOps(SelectionKey.OP_READ); 75 } 76 } 77 78 static class ClientRecord { 79 public SocketAddress clientAddress; 80 public ByteBuffer buffer = ByteBuffer.allocate(ECHOMAX); 81 } 82 }
|
UDPEchoServerSelector.java
分享到:
相关推荐
UDP,即用户数据报协议,是TCP/IP协议栈中的一个无连接协议,位于传输层,与IP协议一起工作。UDP不保证数据包的顺序、完整性和可靠性,因此适用于对实时性要求高但可以容忍数据丢失的场景,如网络视频会议。 设计中...
本文总结了计算机网络原理的多个计算题目及其答案,涵盖了数据传输时间、时延、信道传输速率、UDP 数据报、IP 数据报、PPP 帧、令牌环网、检测令牌丢失、PCM 编码、QAM-16 调制方式等多方面的知识点。 1. 数据传输...
UDP(User Datagram Protocol)协议是“用户数据报协议”,它是一种无连接的协议,当计算机利用 UDP 协议进行数据传输的时候,发送方只需设置目标 IP 地址和端口号就可以发送数据,连接操作在 UDP 通信中是无意义的...
在C#中,可能通过Socket或者UdpClient类发送和接收数据报,并结合加密算法处理数据。 4. **SPP(Secure Pairwise Protocol)**:SPP可能是自定义的安全协议,用于建立安全的通信信道。在这个实例中,SPP可能包含了...
- UDP使用数据报模式,每个数据包独立发送,不保证顺序和可靠性,但传输速度快。 3. **数据正确性和顺序**: - TCP有错误检测和纠正机制,如校验和、序列号和确认应答,确保数据的正确性,并通过重发控制来处理丢...
1. **UDP协议原理**:了解UDP的基本结构,包括头部字段(源端口号、目的端口号、长度和校验和),以及如何封装和解析UDP数据报。 2. **套接字编程**:在嵌入式系统中,通常使用C语言进行编程,涉及套接字API,如`...
2. 数据传输协议:TCP(传输控制协议)和UDP(用户数据报协议)是常用的网络协议。TCP保证数据的可靠传输,适合对数据完整性要求高的场景;UDP则提供低延迟,适用于实时性要求高的游戏。 3. 负载均衡:通过智能分配...
在计算机网络领域,TCP(传输控制协议)和UDP(用户数据报协议)是两种主要的传输层协议,而GPRS(通用分组无线服务)则是2G移动通信系统中的数据传输技术。这篇学习资料深入探讨了这三者的核心概念、工作原理以及...
IP 数据报要经过互连网中许多路由器的存储转发,但 UDP 用户数据报是在运输层的端到端抽象的逻辑信道中传送的。 TCP 报文段是在运输层抽象的端到端逻辑信道中传送,这种信道是可靠的全双工信道。但这样的信道却不...
例如,当一个IP数据报无法到达目的地时,ICMP会返回一个差错报告报文,其中包含原始IP数据报的头部,包括其UDP或TCP部分的最后8个字节。 运输层负责端到端的数据传输,主要有两种协议:用户数据报协议(UDP)和传输...
UDP(用户数据报协议)是网络层的无连接传输协议,它提供了简单快速的数据传输方式,但不保证数据的顺序或可靠性。这个压缩包的内容可能是关于如何结合UDP和TDMA协议,构建一个高效、可靠的设备控制平台。 描述中...
3. **网络传输协议**:语音数据在网络上传输时,会使用特定的协议,如UDP(用户数据报协议)因其低延迟特性常用于实时通信,而TCP(传输控制协议)则提供可靠的数据传输。 4. **实时传输协议(RTP)**:在网络游戏...
奈氏准则规定了在无噪声信道中,理论上可以达到的最大数据传输速率,而香农公式则给出了在有噪声信道中,最大信息传输速率与信道带宽和信噪比之间的关系。比特是信息的基本单位,表示一位二进制数据,而波特是数据...
* 用户数据报 UDP:用户数据报 UDP 是运输层的重要协议,用于提供不可靠的数据传输服务。 * 连续 ARQ 协议:连续 ARQ 协议是运输层的重要协议,用于描述数据传输的可靠性机制。 * TCP 传输控制协议:TCP 传输控制...
在IT领域,网络通信是至关重要的一个环节,而UDP(用户数据报协议)因其轻量级、快速的特点常被用于实时性要求高的应用场景,如视频传输。本项目"udp_2_video_transmit.tar.gz"正是利用Python实现了基于UDP的两路...
运输层协议概述、用户数据报协议 UDP、传输控制协议 TCP、可靠传输的工作原理、TCP 报文段的首部格式、TCP 可靠传输的实现、TCP 的流量控制、TCP 的拥塞控制、TCP 的运输连接管理、进程之间的通信、运输层的两个主要...
4. **数据传输**:最小广播信道可能采用高效的传输协议,如TCP/IP协议族中的UDP(用户数据报协议),它不提供连接建立和数据确认,因此适合实时性和低延迟的通信需求,减少了信道占用。 5. **安全与隐私保护**:在...
其次,时间触发通信信道通常采用TCP/IP协议栈中的UDP(用户数据报协议)作为基础,因为它提供了更低的延迟和更高的数据传输速率。然而,UDP缺乏TCP的可靠性保证,因此游戏开发者需要自行实现丢失数据的检测和重传...