java 阻塞模式与非阻塞模式

2023-11-01

TCP/IP 阻塞模式与非阻塞模式

  1. package concurrentTest;  
  2.   
  3. import java.io.BufferedReader;  
  4. import java.io.IOException;  
  5. import java.io.InputStreamReader;  
  6. import java.io.PrintWriter;  
  7. import java.net.ServerSocket;  
  8. import java.net.Socket;  
  9. import java.net.UnknownHostException;  
  10.   
  11. /** 
  12.  * TCP/IP的阻塞模式  
  13.  */  
  14. public class TCPBIO {  
  15.       
  16.     /** 
  17.      * 客户端监听事件 
  18.      * @param ipStr IP地址 
  19.      * @param portNum 端口号 
  20.      * */  
  21.     public void clientListen(String ipStr, int portNum)  
  22.     {  
  23.         try {  
  24.             Socket socket = new Socket(ipStr, portNum);  
  25.               
  26.             //创建读取服务器端返回流的BufferReader   
  27.             BufferedReader in = new BufferedReader(new   
  28.                                     InputStreamReader(socket.getInputStream()));  
  29.               
  30.             //创建向服务器写入流的PrintWriter   
  31.             PrintWriter out = new PrintWriter(socket.getOutputStream(), true);  
  32.               
  33.             //向服务器发送字符串信息,此处即使写失败也不会抛出异常,会一直阻塞到   
  34.             //写入操作系统或者网络IO出现异常为止   
  35.             out.println("hello java");  
  36.               
  37.             //阻塞读取服务器端的返回信息,以下代码会阻塞到服务器端返回信息或者网络IO出现异常为止   
  38.             //若希望过段时间后不阻塞,则在socket创建后加入socket.setSoTimeout(time);   
  39.             in.readLine();  
  40.               
  41.         } catch (UnknownHostException e) {  
  42.             // TODO Auto-generated catch block   
  43.             e.printStackTrace();  
  44.         } catch (IOException e) {  
  45.             // TODO Auto-generated catch block   
  46.             e.printStackTrace();  
  47.         }  
  48.           
  49.     }  
  50.       
  51.       
  52.     /** 
  53.      * 服务器端监听事件 
  54.      * @param portNum 端口号 
  55.      * */  
  56.     public void serverListen(int portNum)  
  57.     {  
  58.         ServerSocket ss;  
  59.         try {  
  60.             ss = new ServerSocket(portNum);  
  61.               
  62.             //通过Scoket.getInputStream和Socket.getOutputStream进行读写操作,此方法   
  63.             //会一直阻塞到有客户端发送建立请求   
  64.             Socket socket = ss.accept();  
  65.               
  66.         } catch (IOException e) {  
  67.             // 网络IO异常   
  68.             e.printStackTrace();  
  69.         }  
  70.           
  71.     }  
  72.       
  73.     public static void main(String[] args) {  
  74.         // TODO Auto-generated method stub   
  75.   
  76.     }  
  77.   
  78. }  
package concurrentTest;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.UnknownHostException;

/**
 * TCP/IP的阻塞模式 
 */
public class TCPBIO {
	
	/**
	 * 客户端监听事件
	 * @param ipStr IP地址
	 * @param portNum 端口号
	 * */
	public void clientListen(String ipStr, int portNum)
	{
		try {
			Socket socket = new Socket(ipStr, portNum);
			
			//创建读取服务器端返回流的BufferReader
			BufferedReader in = new BufferedReader(new 
									InputStreamReader(socket.getInputStream()));
			
			//创建向服务器写入流的PrintWriter
			PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
			
			//向服务器发送字符串信息,此处即使写失败也不会抛出异常,会一直阻塞到
			//写入操作系统或者网络IO出现异常为止
			out.println("hello java");
			
			//阻塞读取服务器端的返回信息,以下代码会阻塞到服务器端返回信息或者网络IO出现异常为止
			//若希望过段时间后不阻塞,则在socket创建后加入socket.setSoTimeout(time);
			in.readLine();
			
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * 服务器端监听事件
	 * @param portNum 端口号
	 * */
	public void serverListen(int portNum)
	{
		ServerSocket ss;
		try {
			ss = new ServerSocket(portNum);
			
			//通过Scoket.getInputStream和Socket.getOutputStream进行读写操作,此方法
			//会一直阻塞到有客户端发送建立请求
			Socket socket = ss.accept();
			
		} catch (IOException e) {
			// 网络IO异常
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}


 

  1. <PRE class=java name="code">package concurrentTest;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.InetSocketAddress;  
  5. import java.net.ServerSocket;  
  6. import java.nio.ByteBuffer;  
  7. import java.nio.channels.*;  
  8. import java.util.Set;  
  9.   
  10. /** 
  11.  * TCP/IP的 非阻塞模式  
  12.  */  
  13.   
  14. public class TCPNIO {  
  15.   
  16.     /** 
  17.      * 客户端监听事件 
  18.      * @param ipStr IP地址 
  19.      * @param portNum 端口号 
  20.      * */     
  21.       
  22.     public void clientListen(String ipStr, int portNum, int blockTime)  
  23.     {  
  24.         try {  
  25.             SocketChannel channel = SocketChannel.open();  
  26.               
  27.             //设置为非阻塞模式   
  28.             channel.configureBlocking(false);  
  29.               
  30.             //对于非阻塞模式,立刻返回false,表示连接正在建立中   
  31.             Selector selector = Selector.open();  
  32.               
  33.             //向channel注册selector和感兴趣事件   
  34.             channel.register(selector, SelectionKey.OP_CONNECT);  
  35.               
  36.             //阻塞至有感兴趣的IO事件发生,或者到达超时时间,如果希望一直等待到有感兴趣的   
  37.             //事件发生,可调用无参数的select方法,如果希望不阻塞直接返回目前是否有感兴趣的   
  38.             //事件发生,可调用selectNow方法   
  39.             int nKeys = selector.select(blockTime);  
  40.             SelectionKey sKey = null;  
  41.               
  42.             //nKeys大于0,说明有感兴趣的事件发生   
  43.             if(nKeys > 0)  
  44.             {  
  45.                 Set<SelectionKey> keys = selector.selectedKeys();  
  46.                 for(SelectionKey key:keys)  
  47.                 {  
  48.                     //对于发生连接事件   
  49.                     if(key.isConnectable())  
  50.                     {  
  51.                         SocketChannel sc = (SocketChannel)key.channel();  
  52.                         sc.configureBlocking(false);  
  53.                           
  54.                         //注册感兴趣的IO事件,通常不直接注册写事件,在发送缓冲区未满的情况下   
  55.                         //一直是可写的,所以如果注册了写事件,而又不写数据,则很容易造成CPU消耗100%   
  56.                         sKey = sc.register(selector, SelectionKey.OP_READ);  
  57.                           
  58.                         //完成连接的建立   
  59.                         sc.finishConnect();  
  60.                     }  
  61.                     else if(key.isReadable())//有流可读取   
  62.                     {  
  63.                         ByteBuffer buffer = ByteBuffer.allocate(1024);  
  64.                         SocketChannel sc = (SocketChannel)key.channel();  
  65.                         int readBytes = 0;  
  66.   
  67.                         try {  
  68.                             int ret = 0;  
  69.                             try {  
  70.                                 //读取目前可读的流,sc.read(buffer)返回的是成功复制到bytebuffer中   
  71.                                 //的字节数,为阻塞操作,值可能为0,若到流结尾,返回-1   
  72.                                 while ((ret = sc.read(buffer)) > 0) {  
  73.                                     readBytes += ret;  
  74.                                 }  
  75.                             } finally {  
  76.                                 buffer.flip();  
  77.                             }  
  78.                         } finally{  
  79.                             if(buffer != null)  
  80.                             {  
  81.                                 buffer.clear();  
  82.                             }  
  83.                         }  
  84.                     }  
  85.                     else if(key.isWritable())//可写入流   
  86.                     {  
  87.                         //取消对OP_WRITE事件的注册   
  88.                         ByteBuffer buffer = ByteBuffer.allocate(1024);  
  89.                         key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));  
  90.                         SocketChannel sc = (SocketChannel)key.channel();  
  91.                           
  92.                         //此步为阻塞操作,知道写入操作系统发送缓冲区或者网络IO出现异常   
  93.                         //返回的为成功写入的字节数,若缓冲区已满,返回0   
  94.                         int writeenedSize = sc.write(buffer);  
  95.                           
  96.                         //若未写入,继续注册感兴趣的OP_WRITE事件   
  97.                         if(writeenedSize == 0)  
  98.                         {  
  99.                             key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);  
  100.                         }  
  101.                     }  
  102.                 }  
  103.                   
  104.                 selector.selectedKeys().clear();  
  105.             }  
  106.             /* 
  107.              * 也可以直接调用channel.write完成写 
  108.              * 只有在写入未成功时才注册OP_WRITE事件 
  109.             ByteBuffer buffer = ByteBuffer.allocate(1024); 
  110.             int wSize = channel.write(buffer); 
  111.             if(wSize == 0) 
  112.             { 
  113.                 key.interestOps(key.interestOps() | SelectionKey.OP_WRITE); 
  114.             }*/  
  115.               
  116.         } catch (IOException e) {  
  117.             // TODO Auto-generated catch block   
  118.             e.printStackTrace();  
  119.         }  
  120.     }  
  121.       
  122.       
  123.     /** 
  124.      * 服务器端监听事件 
  125.      * @param portNum 端口号 
  126.      * */  
  127.     public void serverListen(int portNum, int blockTime)  
  128.     {  
  129.         ServerSocketChannel ssc;  
  130.         try {  
  131.             ssc = ServerSocketChannel.open();  
  132.             ServerSocket serverSocket = ssc.socket();             
  133.             serverSocket.bind(new InetSocketAddress(portNum));  
  134.             ssc.configureBlocking(false);  
  135.             Selector selector = Selector.open();  
  136.             ssc.register(selector, SelectionKey.OP_ACCEPT);  
  137.               
  138.             int nKeys = selector.select(blockTime);           
  139.             if(nKeys > 0)  
  140.             {  
  141.                 Set<SelectionKey> keys = selector.selectedKeys();  
  142.                 for(SelectionKey key:keys)  
  143.                 {  
  144.                     if(key.isAcceptable())  
  145.                     {  
  146.                         ServerSocketChannel server = (ServerSocketChannel)key.channel();  
  147.                         SocketChannel sc = server.accept();  
  148.                         if(sc == null)  
  149.                         {  
  150.                             continue;  
  151.                         }  
  152.                         sc.configureBlocking(false);  
  153.                           
  154.                         //注册感兴趣的连接建立事件   
  155.                         sc.register(selector, SelectionKey.OP_READ);  
  156.                     }  
  157.                 }  
  158.             }  
  159.               
  160.         } catch (IOException e) {  
  161.             // TODO Auto-generated catch block   
  162.             e.printStackTrace();  
  163.         }  
  164.           
  165.     }  
  166.       
  167.     public static void main(String[] args) {  
  168.         // TODO Auto-generated method stub   
  169.   
  170.     }  
  171.   
  172. }  
  173. </PRE><BR>  
  174. <BR>  
  175. <PRE></PRE>  
  176. <BR>  
<PRE class=java name="code">package concurrentTest;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Set;

/**
 * TCP/IP的 非阻塞模式 
 */

public class TCPNIO {

	/**
	 * 客户端监听事件
	 * @param ipStr IP地址
	 * @param portNum 端口号
	 * */	
	
	public void clientListen(String ipStr, int portNum, int blockTime)
	{
		try {
			SocketChannel channel = SocketChannel.open();
			
			//设置为非阻塞模式
			channel.configureBlocking(false);
			
			//对于非阻塞模式,立刻返回false,表示连接正在建立中
			Selector selector = Selector.open();
			
			//向channel注册selector和感兴趣事件
			channel.register(selector, SelectionKey.OP_CONNECT);
			
			//阻塞至有感兴趣的IO事件发生,或者到达超时时间,如果希望一直等待到有感兴趣的
			//事件发生,可调用无参数的select方法,如果希望不阻塞直接返回目前是否有感兴趣的
			//事件发生,可调用selectNow方法
			int nKeys = selector.select(blockTime);
			SelectionKey sKey = null;
			
			//nKeys大于0,说明有感兴趣的事件发生
			if(nKeys > 0)
			{
				Set<SelectionKey> keys = selector.selectedKeys();
				for(SelectionKey key:keys)
				{
					//对于发生连接事件
					if(key.isConnectable())
					{
						SocketChannel sc = (SocketChannel)key.channel();
						sc.configureBlocking(false);
						
						//注册感兴趣的IO事件,通常不直接注册写事件,在发送缓冲区未满的情况下
						//一直是可写的,所以如果注册了写事件,而又不写数据,则很容易造成CPU消耗100%
						sKey = sc.register(selector, SelectionKey.OP_READ);
						
						//完成连接的建立
						sc.finishConnect();
					}
					else if(key.isReadable())//有流可读取
					{
						ByteBuffer buffer = ByteBuffer.allocate(1024);
						SocketChannel sc = (SocketChannel)key.channel();
						int readBytes = 0;

						try {
							int ret = 0;
							try {
								//读取目前可读的流,sc.read(buffer)返回的是成功复制到bytebuffer中
								//的字节数,为阻塞操作,值可能为0,若到流结尾,返回-1
								while ((ret = sc.read(buffer)) > 0) {
									readBytes += ret;
								}
							} finally {
								buffer.flip();
							}
						} finally{
							if(buffer != null)
							{
								buffer.clear();
							}
						}
					}
					else if(key.isWritable())//可写入流
					{
						//取消对OP_WRITE事件的注册
						ByteBuffer buffer = ByteBuffer.allocate(1024);
						key.interestOps(key.interestOps() & (~SelectionKey.OP_WRITE));
						SocketChannel sc = (SocketChannel)key.channel();
						
						//此步为阻塞操作,知道写入操作系统发送缓冲区或者网络IO出现异常
						//返回的为成功写入的字节数,若缓冲区已满,返回0
						int writeenedSize = sc.write(buffer);
						
						//若未写入,继续注册感兴趣的OP_WRITE事件
						if(writeenedSize == 0)
						{
							key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
						}
					}
				}
				
				selector.selectedKeys().clear();
			}
			/*
			 * 也可以直接调用channel.write完成写
			 * 只有在写入未成功时才注册OP_WRITE事件
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			int wSize = channel.write(buffer);
			if(wSize == 0)
			{
				key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
			}*/
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	
	/**
	 * 服务器端监听事件
	 * @param portNum 端口号
	 * */
	public void serverListen(int portNum, int blockTime)
	{
		ServerSocketChannel ssc;
		try {
			ssc = ServerSocketChannel.open();
			ServerSocket serverSocket = ssc.socket();			
			serverSocket.bind(new InetSocketAddress(portNum));
			ssc.configureBlocking(false);
			Selector selector = Selector.open();
			ssc.register(selector, SelectionKey.OP_ACCEPT);
			
			int nKeys = selector.select(blockTime);			
			if(nKeys > 0)
			{
				Set<SelectionKey> keys = selector.selectedKeys();
				for(SelectionKey key:keys)
				{
					if(key.isAcceptable())
					{
						ServerSocketChannel server = (ServerSocketChannel)key.channel();
						SocketChannel sc = server.accept();
						if(sc == null)
						{
							continue;
						}
						sc.configureBlocking(false);
						
						//注册感兴趣的连接建立事件
						sc.register(selector, SelectionKey.OP_READ);
					}
				}
			}
			
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
</PRE><BR>
<BR>
<PRE></PRE>
<BR>


 

UDP/IP 阻塞模式与非阻塞模式

 

  1. package concurrentTest;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.DatagramPacket;  
  5. import java.net.DatagramSocket;  
  6. import java.net.InetAddress;  
  7. import java.net.SocketException;  
  8.   
  9. /** 
  10.  * UDP/IP阻塞模式 
  11.  * */  
  12.   
  13. public class UDPBIO {  
  14.   
  15.     /** 
  16.      * 服务器端和客户端类似  
  17.      * @param ipStr IP地址 
  18.      * @param portNum 端口号 
  19.      * */     
  20.       
  21.     public void udpListen(String ipStr, int portNum)  
  22.     {  
  23.         try {  
  24.             //若希望是全双工模式,则启动一个监听端口,承担服务器的职责   
  25.             //若不能绑定到指定端口,则抛出SocketException   
  26.             DatagramSocket serverSocket = new DatagramSocket(portNum);  
  27.             InetAddress server = InetAddress.getByName(ipStr);  
  28.             byte[] buffer = new byte[65507];  
  29.             DatagramPacket receivePacket = new DatagramPacket(buffer,buffer.length);  
  30.             DatagramSocket socket = new DatagramSocket();  
  31.             DatagramPacket packet = new DatagramPacket(buffer,buffer.length,server,portNum);  
  32.               
  33.             //阻塞发送packet到指定的服务器和端口   
  34.             //网络IO异常,抛出IOExceprion   
  35.             //连不上IP和端口,抛出PortUnreachableException   
  36.             socket.send(packet);  
  37.               
  38.             //阻塞并同步读取流信息,如接收到的信息流比packet长,则删除更长的信息   
  39.             serverSocket.receive(receivePacket);  
  40.               
  41.         } catch (SocketException e) {  
  42.             // 若不能绑定到指定端口   
  43.             e.printStackTrace();  
  44.         } catch (IOException e) {  
  45.             // TODO Auto-generated catch block   
  46.             e.printStackTrace();  
  47.         }  
  48.           
  49.     }  
  50.       
  51.     public static void main(String[] args) {  
  52.         // TODO Auto-generated method stub   
  53.   
  54.     }  
  55.   
  56. }  
package concurrentTest;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;

/**
 * UDP/IP阻塞模式
 * */

public class UDPBIO {

	/**
	 * 服务器端和客户端类似 
	 * @param ipStr IP地址
	 * @param portNum 端口号
	 * */	
	
	public void udpListen(String ipStr, int portNum)
	{
		try {
			//若希望是全双工模式,则启动一个监听端口,承担服务器的职责
			//若不能绑定到指定端口,则抛出SocketException
			DatagramSocket serverSocket = new DatagramSocket(portNum);
			InetAddress server = InetAddress.getByName(ipStr);
			byte[] buffer = new byte[65507];
			DatagramPacket receivePacket = new DatagramPacket(buffer,buffer.length);
			DatagramSocket socket = new DatagramSocket();
			DatagramPacket packet = new DatagramPacket(buffer,buffer.length,server,portNum);
			
			//阻塞发送packet到指定的服务器和端口
			//网络IO异常,抛出IOExceprion
			//连不上IP和端口,抛出PortUnreachableException
			socket.send(packet);
			
			//阻塞并同步读取流信息,如接收到的信息流比packet长,则删除更长的信息
			serverSocket.receive(receivePacket);
			
		} catch (SocketException e) {
			// 若不能绑定到指定端口
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}


 

  1. package concurrentTest;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.DatagramSocket;  
  5. import java.net.InetAddress;  
  6. import java.net.InetSocketAddress;  
  7. import java.net.MulticastSocket;  
  8. import java.net.SocketAddress;  
  9. import java.net.SocketException;  
  10. import java.net.UnknownHostException;  
  11. import java.nio.ByteBuffer;  
  12. import java.nio.channels.DatagramChannel;  
  13. import java.nio.channels.SelectionKey;  
  14. import java.nio.channels.Selector;  
  15.   
  16.   
  17. /** 
  18.  * UDP/IP非阻塞模式 
  19.  * */  
  20. public class UDPNIO {  
  21.   
  22.     /** 
  23.      * 服务器端和客户端类似  
  24.      * @param ipStr IP地址 
  25.      * @param portNum 端口号 
  26.      * */         
  27.       
  28.     public void udpListen(String ipStr, int portNum)  
  29.     {  
  30.         try {  
  31.             ByteBuffer buffer = ByteBuffer.allocate(1024);  
  32.             DatagramChannel reveiveChannel = DatagramChannel.open();  
  33.             reveiveChannel.configureBlocking(false);  
  34.             DatagramSocket socket = reveiveChannel.socket();  
  35.             socket.bind(new InetSocketAddress(portNum));  
  36.             Selector selector = Selector.open();  
  37.             reveiveChannel.register(selector, SelectionKey.OP_READ);  
  38.               
  39.             //之后可采取和TCP/IP NIO中对selector遍历方式进行流信息的读取   
  40.             DatagramChannel sendChannel = DatagramChannel.open();  
  41.             sendChannel.configureBlocking(false);  
  42.             SocketAddress target = new InetSocketAddress(InetAddress.getLocalHost(), portNum);  
  43.             sendChannel.connect(target);  
  44.               
  45.             //阻塞写入流,若发送缓冲区已满,返回0,此时可继续注册OP_WRITE事件   
  46.             sendChannel.write(buffer);  
  47.         } catch (SocketException e) {  
  48.             // TODO Auto-generated catch block   
  49.             e.printStackTrace();  
  50.         } catch (IOException e) {  
  51.             // TODO Auto-generated catch block   
  52.             e.printStackTrace();  
  53.         }  
  54.           
  55.     }  
  56.       
  57.       
  58.     /** 
  59.      * 组播 
  60.      * */  
  61.     public void multicaseListen(String ipStr, int portNum)  
  62.     {  
  63.         try {  
  64.             InetAddress groupAddress = InetAddress.getByName(ipStr);  
  65.             MulticastSocket server = new MulticastSocket(portNum);  
  66.               
  67.             //加入组播,若地址为非组播地址,抛出IOException   
  68.             //若不希望再发送数据到组播地址或者不希望再读取数据,可调用server.leaveGroup(组播地址)   
  69.             server.joinGroup(groupAddress);  
  70.             MulticastSocket client = new MulticastSocket();  
  71.             client.joinGroup(groupAddress);  
  72.               
  73.             //   
  74.               
  75.         } catch (UnknownHostException e) {  
  76.             // TODO Auto-generated catch block   
  77.             e.printStackTrace();  
  78.         } catch (IOException e) {  
  79.             // 若地址为非组播地址   
  80.             e.printStackTrace();  
  81.         }  
  82.     }  
  83.       
  84.     public static void main(String[] args) {  
  85.         // TODO Auto-generated method stub   
  86.   
  87.     }  
  88.   
  89. }  
package concurrentTest;

import java.io.IOException;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;
import java.net.SocketAddress;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;


/**
 * UDP/IP非阻塞模式
 * */
public class UDPNIO {

	/**
	 * 服务器端和客户端类似 
	 * @param ipStr IP地址
	 * @param portNum 端口号
	 * */		
	
	public void udpListen(String ipStr, int portNum)
	{
		try {
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			DatagramChannel reveiveChannel = DatagramChannel.open();
			reveiveChannel.configureBlocking(false);
			DatagramSocket socket = reveiveChannel.socket();
			socket.bind(new InetSocketAddress(portNum));
			Selector selector = Selector.open();
			reveiveChannel.register(selector, SelectionKey.OP_READ);
			
			//之后可采取和TCP/IP NIO中对selector遍历方式进行流信息的读取
			DatagramChannel sendChannel = DatagramChannel.open();
			sendChannel.configureBlocking(false);
			SocketAddress target = new InetSocketAddress(InetAddress.getLocalHost(), portNum);
			sendChannel.connect(target);
			
			//阻塞写入流,若发送缓冲区已满,返回0,此时可继续注册OP_WRITE事件
			sendChannel.write(buffer);
		} catch (SocketException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
	}
	
	
	/**
	 * 组播
	 * */
	public void multicaseListen(String ipStr, int portNum)
	{
		try {
			InetAddress groupAddress = InetAddress.getByName(ipStr);
			MulticastSocket server = new MulticastSocket(portNum);
			
			//加入组播,若地址为非组播地址,抛出IOException
			//若不希望再发送数据到组播地址或者不希望再读取数据,可调用server.leaveGroup(组播地址)
			server.joinGroup(groupAddress);
			MulticastSocket client = new MulticastSocket();
			client.joinGroup(groupAddress);
			
			//
			
		} catch (UnknownHostException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// 若地址为非组播地址
			e.printStackTrace();
		}
	}
	
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}


 

 

  1.   服务器代码:  
  2.   
  3.   import java.net.*;  
  4.   
  5.   import java.nio.*;  
  6.   
  7.   import java.nio.channels.*;  
  8.   
  9.   import java.util.*;  
  10.   
  11.   public class server  
  12.   
  13.   {  
  14.   
  15.   ServerSocketChannel ssc ;  
  16.   
  17.   public void start()  
  18.   
  19.   {  
  20.   
  21.   try  
  22.   
  23.   {  
  24.   
  25.   Selector selector = Selector.open();  
  26.   
  27.   ServerSocketChannel ssc=ServerSocketChannel.open();  
  28.   
  29.   ssc.configureBlocking(false);  
  30.   
  31.   ServerSocket ss=ssc.socket();  
  32.   
  33.   InetSocketAddress address = new InetSocketAddress(55555);  
  34.   
  35.   ss.bind(address);  
  36.   
  37.   ssc.register(selector, SelectionKey.OP_ACCEPT);  
  38.   
  39.   System.out.println("端口注册完毕!");  
  40.   
  41.   while(true)  
  42.   
  43.   {  
  44.   
  45.   selector.select();  
  46.   
  47.   Set<SelectionKey> selectionKeys=selector.selectedKeys();  
  48.   
  49.   Iterator<SelectionKey> iter=selectionKeys.iterator();  
  50.   
  51.   ByteBuffer echoBuffer=ByteBuffer.allocate(20);  
  52.   
  53.   SocketChannel sc;  
  54.   
  55.   while(iter.hasNext())  
  56.   
  57.   {  
  58.   
  59.   SelectionKey key=iter.next();  
  60.   
  61.   if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT)  
  62.   
  63.   {  
  64.   
  65.   ServerSocketChannel subssc=(ServerSocketChannel)key.channel();  
  66.   
  67.   sc=subssc.accept();  
  68.   
  69.   sc.configureBlocking(false);  
  70.   
  71.   sc.register(selector, SelectionKey.OP_READ);  
  72.   
  73.   iter.remove();  
  74.   
  75.   System.out.println("有新连接:"+sc);  
  76.   
  77.   }  
  78.   
  79.   else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ)  
  80.   
  81.   {  
  82.   
  83.   sc=(SocketChannel) key.channel();  
  84.   
  85.   while(true)  
  86.   
  87.   {  
  88.   
  89.   echoBuffer.clear();  
  90.   
  91.   int a;  
  92.   
  93.   try  
  94.   
  95.   {  
  96.   
  97.   a=sc.read(echoBuffer);  
  98.   
  99.   }  
  100.   
  101.   catch(Exception e)  
  102.   
  103.   {  
  104.   
  105.   e.printStackTrace();  
  106.   
  107.   break;  
  108.   
  109.   }  
  110.   
  111.   if(a==-1break;  
  112.   
  113.   if(a>0)  
  114.   
  115.   {  
  116.   
  117.   byte[] b=echoBuffer.array();  
  118.   
  119.   System.out.println("接收数据: "+new String(b));  
  120.   
  121.   echoBuffer.flip();  
  122.   
  123.   sc.write(echoBuffer);  
  124.   
  125.   System.out.println("返回数据: "+new String(b));  
  126.   
  127.   }  
  128.   
  129.   }  
  130.   
  131.   sc.close();  
  132.   
  133.   System.out.println("连接结束");  
  134.   
  135.   System.out.println("=============================");  
  136.   
  137.   iter.remove();  
  138.   
  139.   }  
  140.   
  141.   }  
  142.   
  143.   }  
  144.   
  145.   }  
  146.   
  147.   catch (Exception e)  
  148.   
  149.   {  
  150.   
  151.   e.printStackTrace();  
  152.   
  153.   }  
  154.   
  155.   }  
  156.   
  157.   }  
  158.   
  159.   客户端代码:  
  160.   
  161.   import java.net.*;  
  162.   
  163.   import java.nio.*;  
  164.   
  165.   import java.nio.channels.*;  
  166.   
  167.   public class client  
  168.   
  169.   {  
  170.   
  171.   public void start()  
  172.   
  173.   {  
  174.   
  175.   try  
  176.   
  177.   {  
  178.   
  179.   SocketAddress address = new InetSocketAddress("localhost",55555);  
  180.   
  181.   SocketChannel client=SocketChannel.open(address);  
  182.   
  183.   client.configureBlocking(false);  
  184.   
  185.   String a="asdasdasdasddffasfas";  
  186.   
  187.   ByteBuffer buffer=ByteBuffer.allocate(20);  
  188.   
  189.   buffer.put(a.getBytes());  
  190.   
  191.   buffer.clear();  
  192.   
  193.   int d=client.write(buffer);  
  194.   
  195.   System.out.println("发送数据: "+new String(buffer.array()));  
  196.   
  197.   while(true)  
  198.   
  199.   {  
  200.   
  201.   buffer.flip();  
  202.   
  203.   int i=client.read(buffer);  
  204.   
  205.   if(i>0)  
  206.   
  207.   {  
  208.   
  209.   byte[] b=buffer.array();  
  210.   
  211.   System.out.println("接收数据: "+new String(b));  
  212.   
  213.   client.close();  
  214.   
  215.   System.out.println("连接关闭!");  
  216.   
  217.   break;  
  218.   
  219.   }  
  220.   
  221.   }  
  222.   
  223.   }  
  224.   
  225.   catch(Exception e)  
  226.   
  227.   {  
  228.   
  229.   e.printStackTrace();  
  230.   
  231.   }  
  232.   
  233.   }  
  234.   
  235.   }  
  服务器代码:

  import java.net.*;

  import java.nio.*;

  import java.nio.channels.*;

  import java.util.*;

  public class server

  {

  ServerSocketChannel ssc ;

  public void start()

  {

  try

  {

  Selector selector = Selector.open();

  ServerSocketChannel ssc=ServerSocketChannel.open();

  ssc.configureBlocking(false);

  ServerSocket ss=ssc.socket();

  InetSocketAddress address = new InetSocketAddress(55555);

  ss.bind(address);

  ssc.register(selector, SelectionKey.OP_ACCEPT);

  System.out.println("端口注册完毕!");

  while(true)

  {

  selector.select();

  Set<SelectionKey> selectionKeys=selector.selectedKeys();

  Iterator<SelectionKey> iter=selectionKeys.iterator();

  ByteBuffer echoBuffer=ByteBuffer.allocate(20);

  SocketChannel sc;

  while(iter.hasNext())

  {

  SelectionKey key=iter.next();

  if((key.readyOps()&SelectionKey.OP_ACCEPT)==SelectionKey.OP_ACCEPT)

  {

  ServerSocketChannel subssc=(ServerSocketChannel)key.channel();

  sc=subssc.accept();

  sc.configureBlocking(false);

  sc.register(selector, SelectionKey.OP_READ);

  iter.remove();

  System.out.println("有新连接:"+sc);

  }

  else if((key.readyOps()&SelectionKey.OP_READ)==SelectionKey.OP_READ)

  {

  sc=(SocketChannel) key.channel();

  while(true)

  {

  echoBuffer.clear();

  int a;

  try

  {

  a=sc.read(echoBuffer);

  }

  catch(Exception e)

  {

  e.printStackTrace();

  break;

  }

  if(a==-1) break;

  if(a>0)

  {

  byte[] b=echoBuffer.array();

  System.out.println("接收数据: "+new String(b));

  echoBuffer.flip();

  sc.write(echoBuffer);

  System.out.println("返回数据: "+new String(b));

  }

  }

  sc.close();

  System.out.println("连接结束");

  System.out.println("=============================");

  iter.remove();

  }

  }

  }

  }

  catch (Exception e)

  {

  e.printStackTrace();

  }

  }

  }

  客户端代码:

  import java.net.*;

  import java.nio.*;

  import java.nio.channels.*;

  public class client

  {

  public void start()

  {

  try

  {

  SocketAddress address = new InetSocketAddress("localhost",55555);

  SocketChannel client=SocketChannel.open(address);

  client.configureBlocking(false);

  String a="asdasdasdasddffasfas";

  ByteBuffer buffer=ByteBuffer.allocate(20);

  buffer.put(a.getBytes());

  buffer.clear();

  int d=client.write(buffer);

  System.out.println("发送数据: "+new String(buffer.array()));

  while(true)

  {

  buffer.flip();

  int i=client.read(buffer);

  if(i>0)

  {

  byte[] b=buffer.array();

  System.out.println("接收数据: "+new String(b));

  client.close();

  System.out.println("连接关闭!");

  break;

  }

  }

  }

  catch(Exception e)

  {

  e.printStackTrace();

  }

  }

  }

1. 服务端

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.DatagramChannel;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.Set;

public class NioUdpServer {

public static void main(String[] args) {
try {
Selector selector = Selector.open();
DatagramChannel channel = DatagramChannel.open();
channel.configureBlocking(false);
DatagramSocket socket = channel.socket();
socket.bind(new InetSocketAddress(1000));
channel.register(selector, SelectionKey.OP_READ);

ByteBuffer receiveBuffer = ByteBuffer.allocate(1024);
final int PACKAGE_SIZE = 10;
while(true){
int n = selector.select();
if(n == 0){
continue;
}
Set<SelectionKey> readyKeys = selector.selectedKeys();
for(SelectionKey key : readyKeys){
readyKeys.remove(key);

if(key.isReadable()){
DatagramChannel dc = (DatagramChannel)key.channel();
InetSocketAddress client = (InetSocketAddress)dc.receive(receiveBuffer); //接收来自任意一个Client的数据报
key.interestOps(SelectionKey.OP_READ);

System.out.println("client ----> IP: " + client.getAddress().getHostAddress() + ", port: " + client.getPort());
System.out.println("receiveBuffer.position() = " + receiveBuffer.position());
if(receiveBuffer.position() >= PACKAGE_SIZE){
receiveBuffer.flip();
DataInputStream dis = new DataInputStream(new ByteArrayInputStream(receiveBuffer.array()));
System.out.println(dis.readInt());
BufferedReader d = new BufferedReader(new InputStreamReader(dis));
System.out.println(d.readLine());

receiveBuffer.clear();
}else{
dc.register(selector, SelectionKey.OP_READ);
}
}//if
}
}//while
} catch (IOException e) {
e.printStackTrace();
}

}

}


Java NIO学习-UDP的例子

这几天需要实现一个底层基于UDP的协议,该协议底层使用UDP传输但是具有拥塞控制、超时重发、数据确认等功能又比TCP简单 (RUDP,Reliable UDP)。在实现协议底层的UDP服务时准备使用Java的NIO,在网上查资料都是以TCP为例讲的,于是自己研究了一下基于UDP的NIO。

NIO的思路是基于多路选择的,即由原来的每个连接都由一个线程来等待消息,改为每个连接都在选择器上注册,由选择器来等待。当然NIO引入了很多新的概念,如Channel,Buffer、Charset、Selector等,使得编程更简洁、更面向对象化。

下面贴出用NIO API改造成UDP示例代码,注意其中使用Charset来编码解码的过程(当然Charset还支持很多其他编码不仅局限于默认编码)以及Buffer的使用。


  1. package sinpo.usagedemo;   
  2.   
  3. import java.net.DatagramSocket;   
  4. import java.net.InetSocketAddress;   
  5. import java.net.SocketAddress;   
  6. import java.nio.ByteBuffer;   
  7. import java.nio.CharBuffer;   
  8. import java.nio.channels.DatagramChannel;   
  9. import java.nio.channels.SelectionKey;   
  10. import java.nio.channels.Selector;   
  11. import java.nio.charset.Charset;   
  12. import java.util.Iterator;   
  13. import java.util.Set;   
  14.   
  15. /** 
  16.  * @author 徐辛波(sinpo.xu@hotmail.com) Oct 19, 2008 
  17.  */  
  18. public class UDPServer extends Thread {  
  19.     public void run() {  
  20.         Selector selector = null;  
  21.         try {  
  22.             DatagramChannel channel = DatagramChannel.open();  
  23.             DatagramSocket socket = channel.socket();  
  24.             channel.configureBlocking(false);  
  25.             socket.bind(new InetSocketAddress(5057));  
  26.   
  27.             selector = Selector.open();  
  28.             channel.register(selector, SelectionKey.OP_READ);  
  29.         } catch (Exception e) {  
  30.             e.printStackTrace();  
  31.         }  
  32.   
  33.         ByteBuffer byteBuffer = ByteBuffer.allocate(65536);  
  34.         while (true) {  
  35.             try {  
  36.                 int eventsCount = selector.select();  
  37.                 if (eventsCount > 0) {  
  38.                     Set selectedKeys = selector.selectedKeys();  
  39.                     Iterator iterator = selectedKeys.iterator();  
  40.                     while (iterator.hasNext()) {  
  41.                         SelectionKey sk = (SelectionKey) iterator.next();  
  42.                         iterator.remove();  
  43.                         if (sk.isReadable()) {  
  44.                             DatagramChannel datagramChannel = (DatagramChannel) sk  
  45.                                     .channel();  
  46.                             SocketAddress sa = datagramChannel  
  47.                                     .receive(byteBuffer);  
  48.                             byteBuffer.flip();  
  49.   
  50.                             // 测试:通过将收到的ByteBuffer首先通过缺省的编码解码成CharBuffer 再输出   
  51.                             CharBuffer charBuffer = Charset.defaultCharset()  
  52.                                     .decode(byteBuffer);  
  53.                             System.out.println("receive message:"  
  54.                                     + charBuffer.toString());  
  55.                             byteBuffer.clear();  
  56.   
  57.                             String echo = "This is the reply message from 服务器。";  
  58.                             ByteBuffer buffer = Charset.defaultCharset()  
  59.                                     .encode(echo);  
  60.                             datagramChannel.write(buffer);  
  61.                         }  
  62.                     }  
  63.                 }  
  64.             } catch (Exception e) {  
  65.                 e.printStackTrace();  
  66.             }  
  67.         }  
  68.   
  69.     }  
  70.   
  71.     public static void main(String[] args) {  
  72.         new UDPServer().start();  
  73.     }  
  74. }  
 package sinpo.usagedemo; 
 
 import java.net.DatagramSocket; 
 import java.net.InetSocketAddress; 
 import java.net.SocketAddress; 
 import java.nio.ByteBuffer; 
 import java.nio.CharBuffer; 
 import java.nio.channels.DatagramChannel; 
 import java.nio.channels.SelectionKey; 
 import java.nio.channels.Selector; 
 import java.nio.charset.Charset; 
 import java.util.Iterator; 
 import java.util.Set; 
 
 /**
  * @author 徐辛波(sinpo.xu@hotmail.com) Oct 19, 2008
  */
 public class UDPServer extends Thread {
 	public void run() {
 		Selector selector = null;
 		try {
 			DatagramChannel channel = DatagramChannel.open();
 			DatagramSocket socket = channel.socket();
 			channel.configureBlocking(false);
 			socket.bind(new InetSocketAddress(5057));
 
 			selector = Selector.open();
 			channel.register(selector, SelectionKey.OP_READ);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
 
 		ByteBuffer byteBuffer = ByteBuffer.allocate(65536);
 		while (true) {
 			try {
 				int eventsCount = selector.select();
 				if (eventsCount > 0) {
 					Set selectedKeys = selector.selectedKeys();
 					Iterator iterator = selectedKeys.iterator();
 					while (iterator.hasNext()) {
 						SelectionKey sk = (SelectionKey) iterator.next();
 						iterator.remove();
 						if (sk.isReadable()) {
 							DatagramChannel datagramChannel = (DatagramChannel) sk
 									.channel();
 							SocketAddress sa = datagramChannel
 									.receive(byteBuffer);
 							byteBuffer.flip();
 
 							// 测试:通过将收到的ByteBuffer首先通过缺省的编码解码成CharBuffer 再输出
 							CharBuffer charBuffer = Charset.defaultCharset()
 									.decode(byteBuffer);
 							System.out.println("receive message:"
 									+ charBuffer.toString());
 							byteBuffer.clear();
 
 							String echo = "This is the reply message from 服务器。";
 							ByteBuffer buffer = Charset.defaultCharset()
 									.encode(echo);
 							datagramChannel.write(buffer);
 						}
 					}
 				}
 			} catch (Exception e) {
 				e.printStackTrace();
 			}
 		}
 
 	}
 
 	public static void main(String[] args) {
 		new UDPServer().start();
 	}
 }
 
Client:

  1. package sinpo.usagedemo;  
  2.   
  3. import java.net.InetSocketAddress;  
  4. import java.net.SocketAddress;  
  5. import java.nio.ByteBuffer;  
  6. import java.nio.channels.DatagramChannel;  
  7. import java.nio.channels.SelectionKey;  
  8. import java.nio.channels.Selector;  
  9. import java.nio.charset.Charset;  
  10. import java.util.Iterator;  
  11. import java.util.Set;  
  12.   
  13. /** 
  14.  * @author 徐辛波(sinpo.xu@hotmail.com) Oct 19, 2008 
  15.  */  
  16. public class UDPClient extends Thread {  
  17.     public void run() {  
  18.         DatagramChannel channel = null;  
  19.         Selector selector = null;  
  20.         try {  
  21.             channel = DatagramChannel.open();  
  22.             channel.configureBlocking(false);  
  23.             SocketAddress sa = new InetSocketAddress("localhost"5057);  
  24.             channel.connect(sa);  
  25.         } catch (Exception e) {  
  26.             e.printStackTrace();  
  27.         }  
  28.   
  29.         try {  
  30.             selector = Selector.open();  
  31.             channel.register(selector, SelectionKey.OP_READ);  
  32.             channel.write(Charset.defaultCharset().encode("Tell me your time"));  
  33.         } catch (Exception e) {  
  34.             e.printStackTrace();  
  35.         }  
  36.   
  37.         ByteBuffer byteBuffer = ByteBuffer.allocate(100);  
  38.         while (true) {  
  39.             try {  
  40.                 int eventsCount = selector.select();  
  41.                 if (eventsCount > 0) {  
  42.                     Set selectedKeys = selector.selectedKeys();  
  43.                     Iterator iterator = selectedKeys.iterator();  
  44.                     while (iterator.hasNext()) {  
  45.                         SelectionKey sk = (SelectionKey) iterator.next();  
  46.                         iterator.remove();  
  47.                         if (sk.isReadable()) {  
  48.                             DatagramChannel datagramChannel = (DatagramChannel) sk  
  49.                                     .channel();  
  50.                             datagramChannel.read(byteBuffer);  
  51.                             byteBuffer.flip();  
  52.   
  53.                             // TODO 将报文转化为RUDP消息并调用RUDP协议处理器来处理   
  54.   
  55.                             System.out.println(Charset.defaultCharset()  
  56.                                     .decode(byteBuffer).toString());  
  57.                             byteBuffer.clear();  
  58.                             datagramChannel.write(Charset.defaultCharset()  
  59.                                     .encode("Tell me your time"));  
  60.                         }  
  61.                     }  
  62.                 }  
  63.             } catch (Exception e) {  
  64.                 e.printStackTrace();  
  65.             }  
  66.         }  
  67.   
  68.     }  
  69. }  
 package sinpo.usagedemo;
 
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
 import java.nio.ByteBuffer;
 import java.nio.channels.DatagramChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.charset.Charset;
 import java.util.Iterator;
 import java.util.Set;
 
 /**
  * @author 徐辛波(sinpo.xu@hotmail.com) Oct 19, 2008
  */
 public class UDPClient extends Thread {
 	public void run() {
 		DatagramChannel channel = null;
 		Selector selector = null;
 		try {
 			channel = DatagramChannel.open();
 			channel.configureBlocking(false);
 			SocketAddress sa = new InetSocketAddress("localhost", 5057);
 			channel.connect(sa);
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
 
 		try {
 			selector = Selector.open();
 			channel.register(selector, SelectionKey.OP_READ);
 			channel.write(Charset.defaultCharset().encode("Tell me your time"));
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
 
 		ByteBuffer byteBuffer = ByteBuffer.allocate(100);
 		while (true) {
 			try {
 				int eventsCount = selector.select();
 				if (eventsCount > 0) {
 					Set selectedKeys = selector.selectedKeys();
 					Iterator iterator = selectedKeys.iterator();
 					while (iterator.hasNext()) {
 						SelectionKey sk = (SelectionKey) iterator.next();
 						iterator.remove();
 						if (sk.isReadable()) {
 							DatagramChannel datagramChannel = (DatagramChannel) sk
 									.channel();
 							datagramChannel.read(byteBuffer);
 							byteBuffer.flip();
 
 							// TODO 将报文转化为RUDP消息并调用RUDP协议处理器来处理
 
 							System.out.println(Charset.defaultCharset()
 									.decode(byteBuffer).toString());
 							byteBuffer.clear();
 							datagramChannel.write(Charset.defaultCharset()
 									.encode("Tell me your time"));
 						}
 					}
 				}
 			} catch (Exception e) {
 				e.printStackTrace();
 			}
 		}
 
 	}
 }

Java异步socket

用异步输入输出流编写Socket进程通信程序 
在Merlin中加入了用于实现异步输入输出机制的应用程序接口 包:java.nio(新的输入输出包,定义了很多基本类型缓冲(Buffer)),java.nio.channels(通道及选择器等,用于异步输入 输出),java.nio.charset(字符的编码解码)。通道(Channel)首先在选择器(Selector)中注册自己感兴趣的事件,当相应 的事件发生时,选择器便通过选择键(SelectionKey)通知已注册的通道。然后通道将需要处理的信息,通过缓冲(Buffer)打包,编码/解 码,完成输入输出控制。

通道介绍: 
这里主要介绍ServerSocketChannel和 SocketChannel.它们都是可选择的(selectable)通道,分别可以工作在同步和异步两种方式下(注意,这里的可选择不是指可以选择两 种工作方式,而是指可以有选择的注册自己感兴趣的事件)。可以用channel.configureBlocking(Boolean )来设置其工作方式。与以前版本的API相比较,ServerSocketChannel就相当于 ServerSocket(ServerSocketChannel封装了ServerSocket),而SocketChannel就相当于 Socket(SocketChannel封装了Socket)。当通道工作在同步方式时,编程方法与以前的基本相似,这里主要介绍异步工作方式。

所 谓异步输入输出机制,是指在进行输入输出处理时,不必等到输入输出处理完毕才返回。所以异步的同义语是非阻塞(None Blocking)。在服务器端,ServerSocketChannel通过静态函数open()返回一个实例serverChl。然后该通道调用 serverChl.socket().bind()绑定到服务器某端口,并调用register(Selector sel, SelectionKey.OP_ACCEPT)注册OP_ACCEPT事件到一个选择器中(ServerSocketChannel只可以注册 OP_ACCEPT事件)。当有客户请求连接时,选择器就会通知该通道有客户连接请求,就可以进行相应的输入输出控制了;在客户端,clientChl实 例注册自己感兴趣的事件后(可以是OP_CONNECT,OP_READ,OP_WRITE的组合),调用 clientChl.connect(InetSocketAddress )连接服务器然后进行相应处理。注意,这里的连接是异步的,即会立即返回而继续执行后面的代码。

选择器和选择键介绍: 
选择器 (Selector)的作用是:将通道感兴趣的事件放入队列中,而不是马上提交给应用程序,等已注册的通道自己来请求处理这些事件。换句话说,就是选择器 将会随时报告已经准备好了的通道,而且是按照先进先出的顺序。那么,选择器是通过什么来报告的呢?选择键(SelectionKey)。选择键的作用就是 表明哪个通道已经做好了准备,准备干什么。你也许马上会想到,那一定是已注册的通道感兴趣的事件。不错,例如对于服务器端serverChl来说,可以调 用key.isAcceptable()来通知serverChl有客户端连接请求。相应的函数还 有:SelectionKey.isReadable(),SelectionKey.isWritable()。一般的,在一个循环中轮询感兴趣的事件 (具体可参照下面的代码)。如果选择器中尚无通道已注册事件发生,调用Selector.select()将阻塞,直到有事件发生为止。另外,可以调用 selectNow()或者select(long timeout)。前者立即返回,没有事件时返回0值;后者等待timeout时间后返回。一个选择器最多可以同时被63个通道一起注册使用。
应用实例: 
下面是用异步输入输出机制实现的客户/服务器实例程序――程序清单1(限于篇幅,只给出了服务器端实现,读者可以参照着实现客户端代码): 

程序类图

  1. import java.io.IOException;  
  2.  import java.net.InetAddress;  
  3.  import java.net.InetSocketAddress;  
  4.  import java.net.Socket;  
  5.  import java.nio.ByteBuffer;  
  6.  import java.nio.CharBuffer;  
  7.  import java.nio.channels.SelectableChannel;  
  8.  import java.nio.channels.SelectionKey;  
  9.  import java.nio.channels.Selector;  
  10.  import java.nio.channels.ServerSocketChannel;  
  11.  import java.nio.channels.SocketChannel;  
  12.  import java.nio.charset.CharacterCodingException;  
  13.  import java.nio.charset.Charset;  
  14.  import java.nio.charset.CharsetDecoder;  
  15.  import java.util.HashMap;  
  16.  import java.util.Iterator;  
  17.  import java.util.Set;  
  18.    
  19.  public class NBlockingServer {  
  20.     int port = 8000;  
  21.     int BUFFERSIZE = 1024;  
  22.     Selector selector = null;  
  23.     ServerSocketChannel serverChannel = null;  
  24.     HashMap clientChannelMap = null;// 用来存放每一个客户连接对应的套接字和通道   
  25.    
  26.     public NBlockingServer(int port) {  
  27.         this.clientChannelMap = new HashMap();  
  28.         this.port = port;  
  29.     }  
  30.    
  31.     public void initialize() throws IOException {  
  32.         // 初始化,分别实例化一个选择器,一个服务器端可选择通道   
  33.         this.selector = Selector.open();  
  34.         this.serverChannel = ServerSocketChannel.open();  
  35.         this.serverChannel.configureBlocking(false);  
  36.         InetAddress localhost = InetAddress.getLocalHost();  
  37.         InetSocketAddress isa = new InetSocketAddress(localhost, this.port);  
  38.         this.serverChannel.socket().bind(isa);// 将该套接字绑定到服务器某一可用端口   
  39.     }  
  40.    
  41.     // 结束时释放资源   
  42.     public void finalize() throws IOException {  
  43.         this.serverChannel.close();  
  44.         this.selector.close();  
  45.     }  
  46.    
  47.     // 将读入字节缓冲的信息解码   
  48.     public String decode(ByteBuffer byteBuffer) throws CharacterCodingException {  
  49.         Charset charset = Charset.forName("ISO-8859-1");  
  50.         CharsetDecoder decoder = charset.newDecoder();  
  51.         CharBuffer charBuffer = decoder.decode(byteBuffer);  
  52.         String result = charBuffer.toString();  
  53.         return result;  
  54.     }  
  55.    
  56.     // 监听端口,当通道准备好时进行相应操作   
  57.     public void portListening() throws IOException, InterruptedException {  
  58.         // 服务器端通道注册OP_ACCEPT事件   
  59.         SelectionKey acceptKey = this.serverChannel.register(this.selector,  
  60.                 SelectionKey.OP_ACCEPT);  
  61.         // 当有已注册的事件发生时,select()返回值将大于0   
  62.         while (acceptKey.selector().select() > 0) {  
  63.             System.out.println("event happened");  
  64.             // 取得所有已经准备好的所有选择键   
  65.             Set readyKeys = this.selector.selectedKeys();  
  66.             // 使用迭代器对选择键进行轮询   
  67.             Iterator iter = readyKeys.iterator();  
  68.             while (iter.hasNext()) {  
  69.                 SelectionKey key = (SelectionKey) iter.next();  
  70.                 iter.remove();  
  71.                 if (key.isReadable()) {// 如果是通道读准备好事件   
  72.                     System.out.println("Readable");  
  73.                     // 取得选择键对应的通道和套接字   
  74.                     SelectableChannel nextReady = (SelectableChannel) key  
  75.                             .channel();  
  76.                     Socket socket = (Socket) key.attachment();  
  77.                     // 处理该事件,处理方法已封装在类ClientChInstance中   
  78.                     this.readFromChannel(socket.getChannel(),  
  79.                             (ClientChInstance) this.clientChannelMap  
  80.                                     .get(socket));  
  81.                 } else if (key.isWritable()) {// 如果是通道写准备好事件   
  82.                     System.out.println("writeable");  
  83.                     // 取得套接字后处理,方法同上   
  84.                     Socket socket = (Socket) key.attachment();  
  85.                     SocketChannel channel = (SocketChannel) socket.getChannel();  
  86.                     this.writeToChannel(channel, "This is from server!");  
  87.                 }  
  88.             }  
  89.         }  
  90.     }  
  91.    
  92.     // 对通道的写操作   
  93.     public void writeToChannel(SocketChannel channel, String message)  
  94.             throws IOException {  
  95.         ByteBuffer buf = ByteBuffer.wrap(message.getBytes());  
  96.         int nbytes = channel.write(buf);  
  97.     }  
  98.    
  99.     // 对通道的读操作   
  100.     public void readFromChannel(SocketChannel channel,  
  101.             ClientChInstance clientInstance) throws IOException,  
  102.             InterruptedException {  
  103.         ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFERSIZE);  
  104.         int nbytes = channel.read(byteBuffer);  
  105.         byteBuffer.flip();  
  106.         String result = this.decode(byteBuffer);  
  107.         // 当客户端发出”@exit”退出命令时,关闭其通道   
  108.         if (result.indexOf("@exit") >= 0) {  
  109.             channel.close();  
  110.         } else {  
  111.             clientInstance.append(result.toString());  
  112.             // 读入一行完毕,执行相应操作   
  113.             if (result.indexOf("/n") >= 0) {  
  114.                 System.out.println("client input" + result);  
  115.                 clientInstance.execute();  
  116.             }  
  117.         }  
  118.     }  
  119.    
  120.     // 该类封装了怎样对客户端的通道进行操作,具体实现可以通过重载execute()方法   
  121.     public class ClientChInstance {  
  122.         SocketChannel channel;  
  123.         StringBuffer buffer = new StringBuffer();  
  124.    
  125.         public ClientChInstance(SocketChannel channel) {  
  126.             this.channel = channel;  
  127.         }  
  128.    
  129.         public void execute() throws IOException {  
  130.             String message = "This is response after reading from channel!";  
  131.             writeToChannel(this.channel, message);  
  132.             buffer = new StringBuffer();  
  133.         }  
  134.    
  135.         // 当一行没有结束时,将当前字窜置于缓冲尾   
  136.         public void append(String values) {  
  137.             buffer.append(values);  
  138.         }  
  139.     }  
  140.    
  141.     // 主程序   
  142.     public static void main(String[] args) {  
  143.         NBlockingServer nbServer = new NBlockingServer(8000);  
  144.         try {  
  145.             nbServer.initialize();  
  146.         } catch (Exception e) {  
  147.             e.printStackTrace();  
  148.             System.exit(-1);  
  149.         }  
  150.         try {  
  151.             nbServer.portListening();  
  152.         } catch (Exception e) {  
  153.             e.printStackTrace();  
  154.         }  
  155.     }  
  156.  }  
import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
 import java.net.Socket;
 import java.nio.ByteBuffer;
 import java.nio.CharBuffer;
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.ServerSocketChannel;
 import java.nio.channels.SocketChannel;
 import java.nio.charset.CharacterCodingException;
 import java.nio.charset.Charset;
 import java.nio.charset.CharsetDecoder;
 import java.util.HashMap;
 import java.util.Iterator;
 import java.util.Set;
 
 public class NBlockingServer {
 	int port = 8000;
 	int BUFFERSIZE = 1024;
 	Selector selector = null;
 	ServerSocketChannel serverChannel = null;
 	HashMap clientChannelMap = null;// 用来存放每一个客户连接对应的套接字和通道
 
 	public NBlockingServer(int port) {
 		this.clientChannelMap = new HashMap();
 		this.port = port;
 	}
 
 	public void initialize() throws IOException {
 		// 初始化,分别实例化一个选择器,一个服务器端可选择通道
 		this.selector = Selector.open();
 		this.serverChannel = ServerSocketChannel.open();
 		this.serverChannel.configureBlocking(false);
 		InetAddress localhost = InetAddress.getLocalHost();
 		InetSocketAddress isa = new InetSocketAddress(localhost, this.port);
 		this.serverChannel.socket().bind(isa);// 将该套接字绑定到服务器某一可用端口
 	}
 
 	// 结束时释放资源
 	public void finalize() throws IOException {
 		this.serverChannel.close();
 		this.selector.close();
 	}
 
 	// 将读入字节缓冲的信息解码
 	public String decode(ByteBuffer byteBuffer) throws CharacterCodingException {
 		Charset charset = Charset.forName("ISO-8859-1");
 		CharsetDecoder decoder = charset.newDecoder();
 		CharBuffer charBuffer = decoder.decode(byteBuffer);
 		String result = charBuffer.toString();
 		return result;
 	}
 
 	// 监听端口,当通道准备好时进行相应操作
 	public void portListening() throws IOException, InterruptedException {
 		// 服务器端通道注册OP_ACCEPT事件
 		SelectionKey acceptKey = this.serverChannel.register(this.selector,
 				SelectionKey.OP_ACCEPT);
 		// 当有已注册的事件发生时,select()返回值将大于0
 		while (acceptKey.selector().select() > 0) {
 			System.out.println("event happened");
 			// 取得所有已经准备好的所有选择键
 			Set readyKeys = this.selector.selectedKeys();
 			// 使用迭代器对选择键进行轮询
 			Iterator iter = readyKeys.iterator();
 			while (iter.hasNext()) {
 				SelectionKey key = (SelectionKey) iter.next();
 				iter.remove();
 				if (key.isReadable()) {// 如果是通道读准备好事件
 					System.out.println("Readable");
 					// 取得选择键对应的通道和套接字
 					SelectableChannel nextReady = (SelectableChannel) key
 							.channel();
 					Socket socket = (Socket) key.attachment();
 					// 处理该事件,处理方法已封装在类ClientChInstance中
 					this.readFromChannel(socket.getChannel(),
 							(ClientChInstance) this.clientChannelMap
 									.get(socket));
 				} else if (key.isWritable()) {// 如果是通道写准备好事件
 					System.out.println("writeable");
 					// 取得套接字后处理,方法同上
 					Socket socket = (Socket) key.attachment();
 					SocketChannel channel = (SocketChannel) socket.getChannel();
 					this.writeToChannel(channel, "This is from server!");
 				}
 			}
 		}
 	}
 
 	// 对通道的写操作
 	public void writeToChannel(SocketChannel channel, String message)
 			throws IOException {
 		ByteBuffer buf = ByteBuffer.wrap(message.getBytes());
 		int nbytes = channel.write(buf);
 	}
 
 	// 对通道的读操作
 	public void readFromChannel(SocketChannel channel,
 			ClientChInstance clientInstance) throws IOException,
 			InterruptedException {
 		ByteBuffer byteBuffer = ByteBuffer.allocate(BUFFERSIZE);
 		int nbytes = channel.read(byteBuffer);
 		byteBuffer.flip();
 		String result = this.decode(byteBuffer);
 		// 当客户端发出”@exit”退出命令时,关闭其通道
 		if (result.indexOf("@exit") >= 0) {
 			channel.close();
 		} else {
 			clientInstance.append(result.toString());
 			// 读入一行完毕,执行相应操作
 			if (result.indexOf("/n") >= 0) {
 				System.out.println("client input" + result);
 				clientInstance.execute();
 			}
 		}
 	}
 
 	// 该类封装了怎样对客户端的通道进行操作,具体实现可以通过重载execute()方法
 	public class ClientChInstance {
 		SocketChannel channel;
 		StringBuffer buffer = new StringBuffer();
 
 		public ClientChInstance(SocketChannel channel) {
 			this.channel = channel;
 		}
 
 		public void execute() throws IOException {
 			String message = "This is response after reading from channel!";
 			writeToChannel(this.channel, message);
 			buffer = new StringBuffer();
 		}
 
 		// 当一行没有结束时,将当前字窜置于缓冲尾
 		public void append(String values) {
 			buffer.append(values);
 		}
 	}
 
 	// 主程序
 	public static void main(String[] args) {
 		NBlockingServer nbServer = new NBlockingServer(8000);
 		try {
 			nbServer.initialize();
 		} catch (Exception e) {
 			e.printStackTrace();
 			System.exit(-1);
 		}
 		try {
 			nbServer.portListening();
 		} catch (Exception e) {
 			e.printStackTrace();
 		}
 	}
 }

小结: 
从 以上程序段可以看出,服务器端没有引入多余线程就完成了多客户的客户/服务器模式。该程序中使用了回调模式(CALLBACK)。需要注意的是,请不要将 原来的输入输出包与新加入的输入输出包混用,因为出于一些原因的考虑,这两个包并不兼容。即使用通道时请使用缓冲完成输入输出控制。该程序在 Windows2000,J2SE1.4下,用telnet测试成功。

传统的Socket是阻塞,像ServerSocket在调用accept方法后便处于阻塞状态等待Client端的连接,所以一般会在Server端使用许多线程,对每一个Socket连接分配一个线程。充分利用并发特性来提高性能。 
但这样会带来许多问题: 
1、Server端创建了许多线程来处理Socket连接,而这些线程大部分的时间都在等待连接, 
也就是说这些线程占了资源,真正做事情的时间却不多。也就是说资源利用率比较低,这就会 
直接导致一个问题,可伸缩性比较差,当接受1000个连接还可以,但增加到10000个或更多时性能会很快下降。像Web服务器Jetty和Tomcat6.x都是用了异步通信模式,来接受客户端的连接,从而很大程度上提高了系统的伸缩性,提高了性能。 
2、由于使用多线程,就会使问题变得复杂,事实如果你敢说精通并发编程,说明你太乐观了,并发编程很容易出错,并且你很难发现问题。并且需要互斥访问一些资源,这往往是个瓶颈,会降低并发性。 
异步的Socket可以解决上面的问题,异步的Socket它是非阻塞的,它尝试去连接,但不管是否能够立即建立连接,它都会立即返回,返回之后它便可以做其他的事情了,但连接真正建立成功,就会有相应的事件来通知,这时候你去做连接成功之后的读写操作了.这个过程,整个线程都是处于忙碌状态,所以只需要单个或者很少几个线程,就可以达到阻塞方式的成百上千的线程的性能. 
类似异步Socket功能应运而生,但Java在jdk1.4才引入这个功能,考虑以前Socket的已提供的功能,而且接口很难一致,Java并没有单独设计异步Socket,而是在java nio中引入了SocketChannel之类的通道来处理这个问题,我们会发现这些通道和对应的Socket提供的接口有很大的相似之处,但这些Channel不是关于Socket的抽象,它们并不处理TCP/UDP协议,而是委托给对Socket来处理。 
这种新的Channel可以在非阻塞的模式下操作。通过注册Selector,使用一种类似观察者模式。其实是Selector不断的轮询连接的端口,我们可以通过Selector的select()方法,这个方法是阻塞的,他会更新就绪操作集的键的数目,并作为返回值返回。我们会通常在判断这个返回值如果不为零,则可能有我们感兴趣的事件发生,然后我们可以通过 

Java代码 
  1. Iterator it = selector.selectedKeys().iterator();  


来得到键的迭代器,这样我们就可以通过遍历这个集合来判断有没有我们感兴趣的事情发生,如果有我们就做一些处理,没有我们可以把这个键remove掉: 

Java代码 
  1. while(it.hasNext()){  
  2.     SelectionKey key = (SelectionKey)it.next();  
  3.     if(key.isAcceptable()){  
  4.        //do something  
  5.       }  
  6.      if(key.isReadable()){  
  7.         //read data           
  8.       }  
  9.     it.remove();//we remove the key beacause of we don't care about it  
  10. }  


一、下面我们介绍一下与Socket相关的各种Channel 
与几种Socket对应的提供了一下几种Channel: 
ServerSocketChannel,SocketChannel,DatagramChannel. 
1、ServerSocketChannel: 

Java代码 
  1. abstract  SocketChannel accept()   
  2.          // 接受到此通道套接字的连接。   
  3. static ServerSocketChannel open()   
  4.          //打开服务器套接字通道。   
  5. abstract  ServerSocket socket()   
  6.           //获取与此通道关联的服务器套接字。   
  7.  int validOps()   
  8.           //返回一个操作集,标识此通道所支持的操作。   


我们发现这个Channel根本不支持读写操作,叫Channel有点名不副实了,但Java中Channel本身的抽象也不一定支持读写操作的,需要实现WriteableChannel和ReadableChannnel接口才能支持。其实ServerSocketChannel本身也不是用于读写 
操作的,它通常通过socket() 方法获取相关的ServerSocket,然后通过ServerSocket 方法bind来绑定端口。ServerSocketChannel提供了open()静态工厂方法来创建ServerSocketChannel对象。同时ServerSocketChannel从AbstractSelectableChannel 
继承了: 

Java代码 
  1. SelectableChannel configureBlocking(boolean block)   
  2.           //调整此通道的阻塞模式。   
  3. SelectionKey register(Selector sel, int ops)   
  4.           //向给定的选择器注册此通道,返回一个选择键。   


这两个方法是最常用的了。通过configureBlocking来设置通道的是否为阻塞模式, 
通过register向给定的选择器注册此通道。 
从上面的过程我们用代码总结一下一般的流程: 

Java代码 
  1.           ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();  
  2.           ServerSocket serverSocket = serverSocketChannel.socket();  
  3.           Selector selector = Selector.open();  
  4.           serverSocket.bind(new InetSocketAddress(port));  
  5.           serverSocketChannel.configureBlocking(false);  
  6.           serverSocketChannel.register(selector,SelectionKey.OP_ACCEPT);  
  7.           while (true) {  
  8.           int n  = selector.select();  
  9.           if( n == 0)  
  10.          continue;  
  11.           Iterator it = selector.selectedKeys().iterator();  
  12.           while(it.hasNext()){  
  13.             SelectionKey key = (SelectionKey)it.next();  
  14.                 if(key.isAcceptable()){  
  15.                 ServerSocketChannel server =  
  16.                                 (ServerSocketChannel) key.channel();  
  17.                                 SocketChannel channel = server.accept();//获取SocketChannel来通信  
  18.                                 registerChannel (selector, channel,  
  19. SelectionKey.OP_READ);       doSomething(channel);  
  20.                 }  
  21.                 if(key.isReadable()){  
  22.                     readDataFormSocket(key);  
  23.                 }  
  24.                 it.remove();  
  25.             }  
  26.           }  


2、SocketChannel: 
SocketChannel通常作为客户端,建立一个对Server端的连接,任何一个SocketChannel 
都是和对应的Socket关联的,但一个Socket并不一定有SocketChannel可以获得。 
同样的SocketChannel也适用静态工厂方法open()来实例化SocketChannel. 
下面来看看最常用的操作: 

引用

public abstract boolean connect(SocketAddress remote) 
                         throws IOException连接此通道的套接字。 
如果此通道处于非阻塞模式,则调用此方法会发起一个非阻塞连接操作。如果立即建立连接(使用本地连接时就是如此),则此方法返回 true。否则此方法返回 false,并且必须在以后通过调用 finishConnect 方法来完成该连接操作。 


我们可以通过 

Java代码 
  1. socketChannel.connect (new InetSocketAddress ("somehost", somePort));  


来建立连接,这个过程是异步的,他会立即返回,如果立即建立连接成功则返回true,否则 
返回false.随后可以通过finishConnect来完成连接的建立。 
另外可通过: 

Java代码 
  1. SocketChannel socketChannel =  
  2. SocketChannel.open (new InetSocketAddress ("somehost", somePort));  

建立连接 
等价于: 

Java代码 
  1. SocketChannel socketChannel = SocketChannel.open();  
  2. socketChannel.connect (new InetSocketAddress ("somehost", somePort));  


下面我们演示一下整个的使用过程: 

Java代码 
  1. InetSocketAddress addr = new InetSocketAddress (host, port);  
  2. SocketChannel sc = SocketChannel.open();  
  3. sc.configureBlocking (false);  
  4. sc.connect (addr);  
  5. while ( ! sc.finishConnect()) {  
  6. doSomethingElse();  
  7. }  
  8. doSomethingWithChannel (sc);  
  9. sc.close();  


3、DatagramChannel 
这个Channel与DatagramSocket相对应,提供了基于UDP协议的数据包的套接字的通道。 
UDP协议是无连接的,DatagramChannelt既可以作为Server端,也可以作为Client端,如果想新创建一个DatagramChannel作为Server端来监听,那么需要绑定到特定的端口或地址和端口的组合,一般过程如下: 

Java代码 
  1. DatagramChannel channel = DatagramChannel.open();  
  2. DatagramSocket socket = channel.socket();  
  3. socket.bind (new InetSocketAddress (portNumber));  


但是一个没有绑定特定端口的DatagramChannel仍然是可以接收数据的,事实上会有一个 
动态生成的端口分配给他。不管DatagramChannel是否绑定到了一个端口,任何一个包的发送都会包含它的地址,下面是DatagramChannel提供的发送和接收数据的方法: 

Java代码 
  1. SocketAddress receive (ByteBuffer dst) throws  
  2. IOException;  
  3. int send (ByteBuffer src, SocketAddress target)  


DatagramChannel并不能保证数据能够发送到目的端,因为UDP协议本身就是不可靠的。 
另外我们再看看DatagramChannel提供了以下下几个方法: 

Java代码 
  1. public abstract DatagramChannel connect (SocketAddress remote)  
  2. throws IOException;  
  3. public abstract boolean isConnected();  
  4. public abstract DatagramChannel disconnect() throws IOException;  


从名字看起来很让人迷惑,因为DatagramChannel就是基于无连接的,为什么还会有 
connect之类的方法呢? 
其实这个Connect的语义和基于流的Socket是不一样的,这里的连接只是制定了远程的 
地址,这样就可以忽略其他地址发来的数据包了。一但使用完connect方法,就不能像其 
他的地址send数据了。但这里的connect和SockectChannel的connect不同,它是可以 
随时disconnect,然后去connect其他的地址的。但使用了connect方法之后,就可以 
像FileChannel那样read,write数据,而不用指名地址了。



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java 阻塞模式与非阻塞模式 的相关文章

  • Java 反射 与 主要API

    控制你的大脑 控制你的行为 你会得到更多 收获很多 文章目录 一 反射相关的主要API 二 代码例子演示 三 反射测试类 一 反射相关的主要API API 名称 代表含义 Java lang class 代表一个类 java lang re
  • (java基础知识)HashMap排序,Comparator接口详解

    对于List 可以调用Collections工具类的sort 方法 直接进行排序 HashMap 就没这么幸福了 其实 只要了解了Comparator这个接口之后 HashMap的排序也就不难了 无论是根据key 还是根据value排序 这
  • Java 父类 与子类之间的转换

    一 子类的实列化通过父类实现 代码正常 二 基于子类的实列化是通过父类实现 强制转换父类 代码正常 三 父类的实列化不能强制转换为子类 代码错误 提示 java lang ClassCastException 针对第三种情况 建议采用方案
  • java 清除字符串空格

    JAVA中去掉空格 1 String trim trim 是去掉首尾空格 2 str replace 去掉所有空格 包括首尾 中间 String str hell o String str2 str replaceAll System ou
  • Java线程:线程的同步-同步方法

    本文转载至 http lavasoft blog 51cto com 62575 221914 Java线程 线程的同步 同步方法 线程的同步是保证多线程安全访问竞争资源的一种手段 线程的同步是Java多线程编程的难点 往往开发者搞不清楚什
  • Java线程:线程的交互

    本文转载至 http lavasoft blog 51cto com 62575 99157 线程交互是比较复杂的问题 SCJP要求不很基础 给定一个场景 编写代码来恰当使用等待 通知和通知所有线程 一 线程交互的基础知识 SCJP所要求的
  • java 线程:概念与原理

    本文转载至 http lavasoft blog 51cto com 62575 99150 一 操作系统中线程和进程的概念 现在的操作系统是多任务操作系统 多线程是实现多任务的一种方式 进程是指一个内存中运行的应用程序 每个进程都有自己独
  • java 阻塞模式与非阻塞模式

    TCP IP 阻塞模式与非阻塞模式 java view plain copy print package concurrentTest import java io BufferedReader import java io IOExcep
  • Java线程:新特征-障碍器

    本文转载至 http lavasoft blog 51cto com 62575 222738 Java5中 添加了障碍器类 为了适应一种新的设计需求 比如一个大型的任务 常常需要分配好多子任务去执行 只有当所有子任务都执行完成时候 才能执
  • Java线程:新特征-有返回值的线程

    本文转载至 http lavasoft blog 51cto com 62575 222082 在Java5之前 线程是没有返回值的 常常为了 有 返回值 破费周折 而且代码很不好写 或者干脆绕过这道坎 走别的路了 现在Java终于有可返回
  • Java 数组 初始化方式 和遍历方式

    Java 数组 初始化方式总结 第一种 静态初始化 所谓静态初始化 初始化时由程序员显式指定每个数组元素的初始值 有系统决定数组的长度 简单实例 String strArr 张三 李四 王五 第二种 动态初始化 所谓动态初始化 初始化时由程
  • Java线程:新特征-信号量

    本文转载至 http lavasoft blog 51cto com 62575 222469 Java线程 新特征 信号量 Java的信号量实际上是一个功能完毕的计数器 对控制一定资源的消费与回收有着很重要的意义 信号量常常用于多线程的代
  • 使用 IO 流 读取 本 地 文 件 (两种方式)

    使用IO 流读取本地文件 public class FileReadWrite public static void main String args FileReader fr null try 1 创建读取文件 fr new FileR
  • Java线程:线程的调度-守护线程

    本文转载至 http lavasoft blog 51cto com 62575 221845 Java线程 线程的调度 守护线程 守护线程与普通线程写法上基本么啥区别 调用线程对象的方法setDaemon true 则可以将其设置为守护线
  • 代码质量保障第2讲:单元测试 - 浅谈单元测试

    代码质量保障第2讲 单元测试 浅谈单元测试 本文是代码质量保障第2讲 浅谈单元测试 单元测试 unit testing 是指对软件中的最小可测试单元进行检查和验证 这是基础 所以围绕着单元测试 我从网上搜集和总结了相关的概念 以助你完善体系
  • (Java 基础知识) Java线程池

    ExecutorService 建立多线程的步骤 1 定义线程类 class Handler implements Runnable 2 建立ExecutorService线程池 ExecutorService executorServic
  • java并发包:重入锁与Condition条件

    本文转载至 http blog csdn net a910626 article details 51900941 重入锁 这里介绍一下synchronized wait notify方法的替代品 或者说是增强版 重入锁 重入锁是可以完全替
  • Java线程:新特征-阻塞栈

    本文转载至 http lavasoft blog 51cto com 62575 222530 对于阻塞栈 与阻塞队列相似 不同点在于栈是 后入先出 的结构 每次操作的是栈顶 而队列是 先进先出 的结构 每次操作的是队列头 这里要特别说明一
  • Java线程:线程的调度-休眠

    本文转载至 http lavasoft blog 51cto com 62575 221790 Java线程 线程的调度 休眠 Java线程调度是Java多线程的核心 只有良好的调度 才能充分发挥系统的性能 提高程序的执行效率 这里要明确的
  • java并发包:fork/join

    本文转载至 http blog csdn net a910626 article details 51900967 Fork Join框架是Java7提供了的一个用于并行执行任务的框架 是一个把大任务分割成若干个小任务 最终汇总每个小任务结

随机推荐

  • Vue中路由vue-router的使用

    基本使用 1 安装vue router 命令 npm i vue router 2 应用插件 import VueRouter from vue router Vue use VueRouter 3 编写router配置项 import V
  • python中判断 nan 的几种方式

    float NaN 判断 float NaN float NaN pandas中的 nan 判断 pd isnull df1 df1 是DataFrame对象 也可以是Series对象 pd isna 直接判断DataFrame某一列是否为
  • Springboot自定义ThreadPoolTaskExecutor线程池多线程并发执行异步方法

    1 背景 当前因为工作需求 要发送大量Http请求 经过实践遍历发送需要6小时才能发送完毕 如果单线程发送请求会导致主线程阻塞 就会存在以下问题 前端用户等待响应时间过长 无法进行下一步操作 不利于用户操作系统 响应时间过长超过Tomcat
  • 内存分页

    内存分页 p Description 内存分页 p param records 待分页的数据 param pageNum 当前页码 param pageSize 每页显示的条数 return 分页之后的数据 public static
  • Git——C站最详细的Git教程,一篇学会Git(window\linux通用)

    Git C站最详细的Git教程 一篇学会Git window linux通用 文章目录 Git C站最详细的Git教程 一篇学会Git window linux通用 Git简介 Git 作用 为什么要进行源代码管理 Git的诞生 Git管理
  • vue双向数据绑定指令v-model

    vue双向数据绑定指令v model v model 被称为双向数据绑定指令 就是Vue实例对数据进行修改 页面会立即感知 相反页面对数据进行修改 Vue内部也会立即感知 v model 是vue中唯一实现双向数据绑定的指令 v bind
  • mybatis增删改查的写法集合

    增删改查的写法集合 注意 xml文件尽量不要注释 Usermapping public interface UserMapping 查询 List
  • mysql建_mysql简单建表

    NULL 和 NOT NULL 修饰符 可以在每个字段后面都加上这NULL 或 NOT NULL 修饰符来指定该字段是否可以为空 NULL 还是说必须填上数据 NOT NULL MySQL默认情况下指定字段为NULL修饰符 如果一个字段指定
  • 《Kafka系列》Java测试远程连接Kafka,实现生产者和消费者,发现两者数据不通?

    Java测试远程连接Kafka 实现生产者和消费者 发现两者数据不通 错误显示 错误排除 1 在网上看到有这种方法 修改Kafka下的conf下的server properties文件 cd opt apps kafka conf serv
  • Stream流

    概念 是JDK1 8的新语法 和IO流不是一个东西相当于流水线 很方便的对数据进行加工 Stream流把真正的函数式编程风格引入到Java中 代码简洁 Stream流不能直接修改数据源中的数据 不使用Stream流的优势是加工处理数据 每个
  • buuctf_Exec

    0x01 题目链接 BUUCTF在线评测BUUCTF 是一个 CTF 竞赛和训练平台 为各位 CTF 选手提供真实赛题在线复现等服务 https buuoj cn challenges 0x02 题目 打开题目就看到大大的PING 二话不说
  • 在存储过程中使用了DML语句要不要调用COMMIT?

    要调用commit语句 或者正常退出sqlplus 系统会自动提交 dml语句不能自动提交 ddl语句和dcl语句可以自动提交 转自 http bbs csdn net topics 80160481
  • 胶囊体阴影

    官方介绍 虚幻引擎现在支持非常柔滑的间接阴影 由代表角色的胶囊体来进行投影 通常 在受间接光照时 并不会产生阴影 除非是屏幕空间环境遮罩 间接投影需要做的非常柔滑 因为间接光照是来自很多不同的方向 因此 传统的阴影贴图做法的效果并不好 间接
  • android windows 安装

    转自 http www cnblogs com skynet archive 2010 04 12 1709892 html 本系列适合0基础的人员 因为我就是从0开始的 此系列记录我步入Android开发的一些经验分享 望与君共勉 作为A
  • 安防监控视频云存储平台EasyNVR通道频繁离线的原因排查与解决

    安防视频监控汇聚EasyNVR视频集中存储平台 是基于RTSP Onvif协议的安防视频平台 可支持将接入的视频流进行全平台 全终端分发 分发的视频流包括RTSP RTMP HTTP FLV WS FLV HLS WebRTC等格式 为了满
  • MATLAB神经网络编程(四)——线性神经网络的实现与局限

    MATLAB神经网络编程 化学工业出版社 读书笔记 第四章 前向型神经网络 4 2 线性神经网络 本文是 MATLAB神经网络编程 书籍的阅读笔记 其中涉及的源码 公式 原理都来自此书 若有不理解之处请参阅原书 一 线性神经网络的实现 线性
  • vue 中 elementui Dropdown 下拉菜单中 选项的click事件

  • gcc/g++交叉编译*.c/*.cpp程序时的配置

    CFLAGS I PWD src CFLAGS I third party hisi include CFLAGS L third party hisi lib CXXFLAGS I PWD src CXXFLAGS I third par
  • 电脑网络故障:LSP造成?

    问题 1 什么是LSP 删除了什么才导致了不能上网 LSP 为什么能影响网络 其内部的原理机制是什么 网络连接正常但无法上网 能ping通外网DNS 解决方法 2013 11 03 00 47 17 转载 标签 辅助工具 在线聊天 解决方法
  • java 阻塞模式与非阻塞模式

    TCP IP 阻塞模式与非阻塞模式 java view plain copy print package concurrentTest import java io BufferedReader import java io IOExcep