1.接口:
class="java">import java.nio.channels.SelectionKey; import java.io.IOException; public interface EchoProtocol { void handleAccept(SelectionKey key) throws IOException; void handleRead(SelectionKey key) throws IOException; void handleWrite(SelectionKey key) throws IOException; }
?2.实现:
import java.net.SocketAddress; import java.nio.channels.*; import java.nio.ByteBuffer; import java.io.IOException; public class UDPEchoSelectorProtocol implements EchoProtocol { private static final int ECHOMAX = 255; // Maximum size of echo datagram static class ClientRecord { public SocketAddress clientAddress; public ByteBuffer buffer = ByteBuffer.allocate(ECHOMAX); } public void handleAccept(SelectionKey key) throws IOException { } public void handleRead(SelectionKey key) throws IOException { DatagramChannel channel = (DatagramChannel) key.channel(); ClientRecord clntRec = (ClientRecord) key.attachment(); clntRec.buffer.clear(); // Prepare buffer for receiving clntRec.clientAddress = channel.receive(clntRec.buffer); if (clntRec.clientAddress != null) { // Did we receive something? // Register write with the selector key.interestOps(SelectionKey.OP_WRITE); } } public void handleWrite(SelectionKey key) throws IOException { DatagramChannel channel = (DatagramChannel) key.channel(); ClientRecord clntRec = (ClientRecord) key.attachment(); clntRec.buffer.flip(); // Prepare buffer for sending int bytesSent = channel.send(clntRec.buffer, clntRec.clientAddress); if (bytesSent != 0) { // Buffer completely written? // No longer interested in writes key.interestOps(SelectionKey.OP_READ); } } }
?
二、NIO?UDP客户端:
import java.net.InetSocketAddress; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.DatagramChannel; public class UDPEchoClientNonblocking { private static final int TIMEOUT = 3000; // Resend timeout (milliseconds) private static final int MAXTRIES = 255; // Maximum retransmissions public static void main(String args[]) throws Exception { // Convert input String to bytes using the default charset byte[] bytesToSend = "0123456789abcdefghijklmnopqrstuvwxyz".getBytes(); // Create channel and set to nonblocking DatagramChannel datagramChannel = DatagramChannel.open(); datagramChannel.configureBlocking(false); datagramChannel.socket().setSoTimeout(TIMEOUT); ByteBuffer writeBuf = ByteBuffer.wrap(bytesToSend); ByteBuffer readBuf = ByteBuffer.allocate(MAXTRIES); datagramChannel = datagramChannel.connect(new InetSocketAddress("127.0.0.1", 5500)); int totalBytesRcvd = 0; // Total bytes received so far int bytesRcvd; // Bytes received in last read while (totalBytesRcvd < bytesToSend.length) { if (writeBuf.hasRemaining()) { datagramChannel.write(writeBuf); } if ((bytesRcvd = datagramChannel.read(readBuf)) == -1) { throw new SocketException("Connection closed prematurely"); } totalBytesRcvd += bytesRcvd; System.out.print("."); // Do something else } System.out.println("Received: " + new String(readBuf.array(), 0, totalBytesRcvd)); datagramChannel.close(); } }
?
三、NIO?UDP服务端:
import java.io.IOException; import java.net.InetSocketAddress; import java.nio.channels.*; import java.util.Iterator; public class UDPEchoServerSelector { private static final int TIMEOUT = 3000; // Wait timeout (milliseconds) public static void main(String[] args) throws IOException { // Create a selector to multiplex client connections. Selector selector = Selector.open(); DatagramChannel channel = DatagramChannel.open(); channel.configureBlocking(false); channel.socket().bind(new InetSocketAddress(5500)); channel.register(selector, SelectionKey.OP_READ, new UDPEchoSelectorProtocol.ClientRecord()); UDPEchoSelectorProtocol echoSelectorProtocol = new UDPEchoSelectorProtocol(); while (true) { // Run forever, receiving and echoing datagrams // Wait for task or until timeout expires if (selector.select(TIMEOUT) == 0) { System.out.print("."); continue; } // Get iterator on set of keys with I/O to process Iterator<SelectionKey> keyIter = selector.selectedKeys().iterator(); while (keyIter.hasNext()) { SelectionKey key = keyIter.next(); // Key is bit mask // Client socket channel has pending data? if (key.isReadable()) echoSelectorProtocol.handleRead(key); // Client socket channel is available for writing and // key is valid (i.e., channel not closed). if (key.isValid() && key.isWritable()) echoSelectorProtocol.handleWrite(key); keyIter.remove(); } } } }
?
?
?参考:
1.《Java TCP/IP Socket编程(原书第2版)》