DatagramChannel
最后一個socket通道是DatagramChannel。正如SocketChannel對應Socket,ServerSocketChannel對應ServerSocket,每一個DatagramChannel對象也有一個關聯(lián)的DatagramSocket對象。不過原命名模式在此并未適用:“DatagramSocketChannel”顯得有點笨拙,因此采用了簡潔的“DatagramChannel”名稱。正如SocketChannel模擬連接導向的流協(xié)議(如TCP/IP),DatagramChannel則模擬包導向的無連接協(xié)議(如UDP/IP):
創(chuàng)建DatagramChannel的模式和創(chuàng)建其他socket通道是一樣的:調用靜態(tài)的open( )方法來創(chuàng)建一個新實例。新DatagramChannel會有一個可以通過調用socket( )方法獲取的對等DatagramSocket對象。DatagramChannel對象既可以充當服務器(監(jiān)聽者)也可以充當客戶端(發(fā)送者)。如果您希望新創(chuàng)建的通道負責監(jiān)聽,那么通道必須首先被綁定到一個端口或地址/端口組合上。綁定DatagramChannel同綁定一個常規(guī)的DatagramSocket沒什么區(qū)別,都是委托對等socket對象上的API實現(xiàn)的:
DatagramChannel channel = DatagramChannel.open( );
DatagramSocket socket = channel.socket( );
socket.bind (new InetSocketAddress (portNumber));
DatagramChannel是無連接的。每個數(shù)據(jù)報(datagram)都是一個自包含的實體,擁有它自己的目的地址及不依賴其他數(shù)據(jù)報的數(shù)據(jù)凈荷。與面向流的的socket不同,DatagramChannel可以發(fā)送單獨的數(shù)據(jù)報給不同的目的地址。同樣,DatagramChannel對象也可以接收來自任意地址的數(shù)據(jù)包。每個到達的數(shù)據(jù)報都含有關于它來自何處的信息(源地址)。
一個未綁定的DatagramChannel仍能接收數(shù)據(jù)包。當一個底層socket被創(chuàng)建時,一個動態(tài)生成的端口號就會分配給它。綁定行為要求通道關聯(lián)的端口被設置為一個特定的值(此過程可能涉及安全檢查或其他驗證)。不論通道是否綁定,所有發(fā)送的包都含有DatagramChannel的源地址(帶端口號)。未綁定的DatagramChannel可以接收發(fā)送給它的端口的包,通常是來回應該通道之前發(fā)出的一個包。已綁定的通道接收發(fā)送給它們所綁定的熟知端口(wellknown port)的包。數(shù)據(jù)的實際發(fā)送或接收是通過send( )和receive( )方法來實現(xiàn)的:
/**
* @author qiz
*/
public class DatagramChannel1 {
public static void main(String[] args) throws IOException {
DatagramChannel datagramChannel = DatagramChannel.open();
datagramChannel.configureBlocking(false);
ByteBuffer allocate = ByteBuffer.allocate(1024);
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()){
String str = scanner.next();
allocate.put((new Date().toString()+"\n"+str).getBytes());
allocate.flip();
datagramChannel.send(allocate,new InetSocketAddress("127.0.0.1",9898));
allocate.clear();
}
datagramChannel.close();
}
}
/**
* @author qiz
*/
public class DatagramChannel2 {
public static void main(String[] args) throws IOException {
DatagramChannel datagramChannel = DatagramChannel.open();
datagramChannel.configureBlocking(false);
datagramChannel.bind(new InetSocketAddress(9898));
Selector selector = Selector.open();
datagramChannel.register(selector, SelectionKey.OP_READ);
while (selector.select() > 0){
Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();
while (iterator.hasNext()){
SelectionKey next = iterator.next();
if (next.isReadable()){
ByteBuffer allocate = ByteBuffer.allocate(1024);
datagramChannel.receive(allocate);
allocate.flip();
System.out.println(new String(allocate.array(),0,allocate.limit()));
allocate.clear();
}
}
iterator.remove();
}
}
}