Java NIOインスタンス-DatagramChannelによるUDPプロトコル転送

13515 ワード

自分の学習ノート(後で問題が発見されたら修正する)
ネット上でudpプロトコルについていくつか見つけて、勉強した後に1つの例を書いて学習のために使います.
他の人の経験に基づいて、以下の内容をまとめました.
TCPとUDPの効率比較:
TCPプロトコルは、効率に対する要求が比較的低いが、正確性に対する要求が比較的高いシーン、または接続概念があるシーンに適用される.一方、UDPプロトコルは、効率に対する要求が比較的高く、正確性に対する要求が比較的低いシーンに適用されます.
TCPとUDP応用シーン:
TCPはネットワークデータベース、分布式高精度計算システムのデータ伝送に用いることができる.UDPはサービスシステムの内部間のデータ伝送に用いることができ、データが比較的多いため、内部システムのローカルエリアネットワーク内のパケット損失率が低く、パケット損失であっても、せいぜい操作が無効である場合、UDPはよく使用される.
インターネットで収集された資料:
TCPバイトフローとUDPデータレポート:http://network.51cto.com/art/201310/413326.htm
TCPとUDPの違い(回転):http://www.cnblogs.com/bizhu/archive/2012/05/12/2497493.html
JAva nio対OP_WRITEの処理はネットの速度の遅い接続を解決します:http://blog.sina.com.cn/s/blog_783ede0301013g5n.html
テストツール:
clumsyツールを使用すると、ネットワークのパケット損失、ネットワーク遅延などの劣悪な環境をシミュレートできます.
ダウンロード先:http://download.csdn.net/detail/foart/8999423
サービス側
package cn;

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 
 * @date 2015-8-7   11:36:25
 */
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.nio.*;

public class DatagramChannelServerDemo {
	// UDP     
	private int port = 9975;
	DatagramChannel channel;
	private Charset charset = Charset.forName("UTF-8");
	private Selector selector = null;

	public DatagramChannelServerDemo() throws IOException {
		try {
			selector = Selector.open();
			channel = DatagramChannel.open();
		} catch (Exception e) {
			selector = null;
			channel = null;
			System.out.println("  ");			
		}
		System.out.println("     ");
	}

	/*      */
	public ByteBuffer encode(String str) {
		return charset.encode(str);
	}

	/*      */
	public String decode(ByteBuffer bb) {
		return charset.decode(bb).toString();
	}

	/*         */
	public void service() throws IOException {
		if(channel==null || selector==null) return;
		channel.configureBlocking(false);
		channel.socket().bind(new InetSocketAddress(port));
		// channel.write(ByteBuffer.wrap(new String("aaaa").getBytes()));
		channel.register(selector, SelectionKey.OP_READ);
		/**    ,     SelectionKey   */
		while (selector.select() > 0) {
			System.out.println("  channel  ");
			/*          SelectionKey    */
			Iterator iterator = selector.selectedKeys().iterator();
			while (iterator.hasNext()) {
				SelectionKey key = null;
				try {
					key = (SelectionKey) iterator.next();
					iterator.remove();

					if (key.isReadable()) {
						reveice(key);
					}
					if (key.isWritable()) {
						// send(key);
					}
				} catch (IOException e) {
					e.printStackTrace();
					try {
						if (key != null) {
							key.cancel();
							key.channel().close();
						}
					} catch (ClosedChannelException cex) {
						e.printStackTrace();
					}
				}
			}
			/*      */
		}
		/*      */
	}

	/*
	 *     receive() IO
	 *             connect(),     <span style="font-family: Arial, Helvetica, sans-serif;">connect()  </span><span style="font-family: Arial, Helvetica, sans-serif;"> read()\write()  ,  java.nio.channels</span>
	 * .NotYetConnectedException     connect()  ,    read write.
	 */
	synchronized public void reveice(SelectionKey key) throws IOException {
		if (key == null)
			return;
		// *** channel.receive()       ***//
		// :           
		DatagramChannel sc = (DatagramChannel) key.channel();
		String content = "";
		// create buffer with capacity of 48 bytes
		ByteBuffer buf = ByteBuffer.allocate(1024);// java   (utf-8)  3  ,gbk   2   
		buf.clear();
		SocketAddress address = sc.receive(buf); // read into buffer.           
		String clientAddress = address.toString().replace("/", "").split(":")[0];
		String clientPost = address.toString().replace("/", "").split(":")[1];

		buf.flip(); // make buffer ready for read
		while (buf.hasRemaining()) {
			buf.get(new byte[buf.limit()]);// read 1 byte at a time
			content += new String(buf.array());
		}
		buf.clear(); // make buffer ready for writing
		System.out.println("  :" + content.trim());
		//     ;udp       ,     ,     
		ByteBuffer buf2 = ByteBuffer.allocate(65507);
		buf2.clear();
		buf2
				.put("       abc..UDP         ,                ,                      ,             。    UDP         ,                ,                      ,             。    UDP         ,                ,                      ,             。    @Q"
						.getBytes());
		buf2.flip();
		channel.send(buf2, new InetSocketAddress(clientAddress,Integer.parseInt(clientPost))); //          

		//     
		ByteBuffer buf3 = ByteBuffer.allocate(65507);
		buf3.clear();
		buf3.put("    ".getBytes());
		buf3.flip();
		channel.send(buf3, new InetSocketAddress(clientAddress, Integer.parseInt(clientPost))); //          
	}

	int y = 0;

	public void send(SelectionKey key) {
		if (key == null)
			return;
		// ByteBuffer buff = (ByteBuffer) key.attachment();
		DatagramChannel sc = (DatagramChannel) key.channel();
		try {
			sc.write(ByteBuffer.wrap(new String("aaaa").getBytes()));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		System.out.println("send2() " + (++y));
	}

	/*      */
	public void sendFile(SelectionKey key) {
		if (key == null)
			return;
		ByteBuffer buff = (ByteBuffer) key.attachment();
		SocketChannel sc = (SocketChannel) key.channel();
		String data = decode(buff);
		if (data.indexOf("get") == -1)
			return;
		String subStr = data.substring(data.indexOf(" "), data.length());
		System.out.println("          " + subStr);
		FileInputStream fileInput = null;
		try {
			fileInput = new FileInputStream(subStr);
			FileChannel fileChannel = fileInput.getChannel();
			fileChannel.transferTo(0, fileChannel.size(), sc);
			fileChannel.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fileInput.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws IOException {
		new DatagramChannelServerDemo().service();
	}
}

クライアント
package cn;

import java.io.IOException;
import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author 
 * @date 2015-8-7   11:36:25
 */
import java.nio.channels.*;
import java.nio.charset.*;
import java.net.*;
import java.io.*;
import java.util.*;
import java.nio.*;

public class DatagramChannelClientDemo {
	// UDP     
	private String serverIp = "127.0.0.1";
	private int port = 9975;
	// private ServerSocketChannel serverSocketChannel;
	DatagramChannel channel;
	private Charset charset = Charset.forName("UTF-8");
	private Selector selector = null;

	public DatagramChannelClientDemo() throws IOException {		
		try {
			selector = Selector.open();
			channel = DatagramChannel.open();
		} catch (Exception e) {
			selector = null;
			channel = null;
			System.out.println("  ");			
		}
		System.out.println("     ");
	}

	/*      */
	public ByteBuffer encode(String str) {
		return charset.encode(str);
	}

	/*      */
	public String decode(ByteBuffer bb) {
		return charset.decode(bb).toString();
	}

	/*         */
	public void service() throws IOException {
		if(channel==null || selector==null) return;
		channel.configureBlocking(false);
		channel.connect(new InetSocketAddress(serverIp, port));//      
		channel.write(ByteBuffer.wrap(new String("         ").getBytes()));
		channel.register(selector, SelectionKey.OP_READ);
		/**    ,     SelectionKey   */
		while (selector.select() > 0) {
			/*          SelectionKey    */
			Iterator iterator = selector.selectedKeys().iterator();
			while (iterator.hasNext()) {
				SelectionKey key = null;
				try {
					key = (SelectionKey) iterator.next();
					iterator.remove();
					if (key.isReadable()) {
						reveice(key);
					}
					if (key.isWritable()) {
						// send(key);
					}
				} catch (IOException e) {
					e.printStackTrace();
					try {
						if (key != null) {
							key.cancel();
							key.channel().close();
						}
					} catch (ClosedChannelException cex) {
						e.printStackTrace();
					}
				}
			}
			/*      */
		}
		/*      */
	}

//	/* 
//	 *   	 read() IO
//	 *  */
//	synchronized public void reveice2(SelectionKey key) throws IOException {
//		if (key == null)
//			return;
//		// *** channel.read()    ***//
//		// :           
//		DatagramChannel sc = (DatagramChannel) key.channel();
//		String content = "";
//		// create buffer with capacity of 48 bytes
//		ByteBuffer buf = ByteBuffer.allocate(3);// java   (utf-8)  3  ,gbk   2   
//		int bytesRead = sc.read(buf); //read into buffer.
//		
//		while (bytesRead >0) {
//		  buf.flip();  //make buffer ready for read
//		  while(buf.hasRemaining()){				      
//			  buf.get(new byte[buf.limit()]); // read 1 byte at a time	
//		      content += new String(buf.array());
//		  }
//		  buf.clear(); //make buffer ready for writing		
//		  bytesRead = sc.read(buf);	
//		}				
//		System.out.println("  :" + content);				
//	}

	/*    */
	synchronized public void reveice(SelectionKey key) throws IOException {
		String threadName = Thread.currentThread().getName();
		if (key == null)
			return;
		try {
			// *** channel.receive()    ***//
			// :           
			DatagramChannel sc = (DatagramChannel) key.channel();
			String content = "";
			//    ;udp       ,     ,     
			ByteBuffer buf = ByteBuffer.allocate(65507);// java   (utf-8)  3  ,gbk   2   
			buf.clear();
			SocketAddress address = sc.receive(buf); // read into buffer.
			String clientAddress = address.toString().replace("/", "").split(":")[0];
			String clientPost = address.toString().replace("/", "").split(":")[1];
			System.out.println(threadName + "\t" + address.toString());
			buf.flip(); // make buffer ready for read
			while (buf.hasRemaining()) {
				buf.get(new byte[buf.limit()]);// read 1 byte at a time
				byte[] tmp = buf.array();
				content += new String(tmp);
			}
			buf.clear(); // make buffer ready for writing 
			System.out.println(threadName + "  :" + content.trim());
			//    
			content = "";
			ByteBuffer buf2 = ByteBuffer.allocate(65507);// java   (utf-8)  3  ,gbk   2   
			buf2.clear();	
			SocketAddress address2 = sc.receive(buf2); // read into buffer.
			buf2.flip(); // make buffer ready for read
			while (buf2.hasRemaining()) {
				buf2.get(new byte[buf2.limit()]);// read 1 byte at a time
				byte[] tmp = buf2.array();
				content += new String(tmp);
			}
			buf2.clear(); // make buffer ready for writing 
			System.out.println(threadName + "  2:" + content.trim());
			
		} catch (PortUnreachableException ex) {
			System.out.println(threadName + "        !");
		}
		send(2);		
	}

	boolean flag = false;

	public void send(int i) {
		if (flag)
			return;
		try {
			// channel.write(ByteBuffer.wrap(new String("         ( "+i+" )").getBytes()));
			// channel.register(selector, SelectionKey.OP_READ );
			ByteBuffer buf2 = ByteBuffer.allocate(48);
			buf2.clear();
			buf2.put(("         ( " + i + " )").getBytes());
			buf2.flip();
			channel.write(buf2);
			channel.register(selector, SelectionKey.OP_READ );
//			int bytesSent = channel.send(buf2, new InetSocketAddress(serverIp,port)); //          
		} catch (IOException e) {
			e.printStackTrace();
		}
		flag = true;
	}

	int y = 0;

	public void send(SelectionKey key) {
		if (key == null)
			return;
		// ByteBuffer buff = (ByteBuffer) key.attachment();
		DatagramChannel sc = (DatagramChannel) key.channel();
		try {
			sc.write(ByteBuffer.wrap(new String("aaaa").getBytes()));
		} catch (IOException e1) {
			e1.printStackTrace();
		}
		System.out.println("send2() " + (++y));
	}

	/*      */
	public void sendFile(SelectionKey key) {
		if (key == null)
			return;
		ByteBuffer buff = (ByteBuffer) key.attachment();
		SocketChannel sc = (SocketChannel) key.channel();
		String data = decode(buff);
		if (data.indexOf("get") == -1)
			return;
		String subStr = data.substring(data.indexOf(" "), data.length());
		System.out.println("          " + subStr);
		FileInputStream fileInput = null;
		try {
			fileInput = new FileInputStream(subStr);
			FileChannel fileChannel = fileInput.getChannel();
			fileChannel.transferTo(0, fileChannel.size(), sc);
			fileChannel.close();
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			try {
				fileInput.close();
			} catch (IOException ex) {
				ex.printStackTrace();
			}
		}
	}

	public static void main(String[] args) throws IOException {
		new Thread(new Runnable() {			
			public void run() {
				try {
					new DatagramChannelClientDemo().service();
				} catch (IOException e) {					
					e.printStackTrace();
				}
			}
		}).start();
		
//		new Thread(new Runnable() {			
//			public void run() {
//				try {
//					new DatagramChannelClientDemo().service();
//				} catch (IOException e) {					
//					e.printStackTrace();
//				}
//			}
//		}).start();
		
	}
}