非阻塞Socket编程

非阻塞Socket通信

       最近在做一个基于TCP协议的数据同步Android移动端,研究发现在通信的过程中,Socket通信分为阻塞式和非阻塞式。
       通俗来讲,阻塞式Socket通信就像一个单行道(SocketChannel),举个例子,有一个煤场,货车装完煤出厂只有一个单行道。煤场默认的出厂方式是按照进入厂区的序号(1,2,3......),厂区里面同时有几个装载机给货车装煤。假如此时,后面序号的几辆车都装满煤,等待出厂,而此时,1号货车没有装满,那么这时,交通处于“阻塞状态”,只有等1号车装满才能畅通。而非阻塞的方式是这样的,此时厂区安排了一个车辆引导员,他负责选择(Selector)已经装满煤的货车先开走,这样出厂单行道是畅通的,“非阻塞方式”,大大提高了运行效率。

       下面给出一个代码示例:
注:界面就不列出了,就一个TextView,代码是未封装前的调试阶段,已通

	SelectionKey key;;
	//定义处理编码和解码的字符集  
	private Charset charset = Charset.forName("UTF-8");
	public String pmsg = "";
	public String msg = "";
	Socket socket = null;
	TextView textview_show;
	static CharsetEncoder encoder = Charset.forName("GB2312").newEncoder();
	
	private Handler mHandler = new Handler() {     
		public void handleMessage(android.os.Message msg) {      
			textview_show.setText((String)msg.obj);     
		}
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		textview_show = (TextView) findViewById(R.id.textview_show_message);
		
		AndroidServer tr = new AndroidServer();
		Thread thread = new Thread(tr);
		thread.start();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}
	
	public class AndroidServer implements Runnable{
    	public void run() {
    		
    		try { 
    			
    			String htmp="";
    			Selector selector = Selector.open();         //静态方法 实例化selector  
    			ServerSocketChannel serverChannel = ServerSocketChannel.open();  
    			serverChannel.configureBlocking(false);  //设置为非阻塞方式,如果为true 那么就为传统的阻塞方式  
		        SharedPreferences preferences = getSharedPreferences("setup", MODE_PRIVATE); 
			Integer getport;
			String ctmp=preferences.getString("jrdk", "");
			if (ctmp.equals("")||ctmp==null){
			    getport=7100;
			}else{
			    getport=Integer.valueOf(ctmp);
			}
				
    			serverChannel.socket().bind(new InetSocketAddress(7100));  //绑定IP 及 端口  
    			serverChannel.register(selector, SelectionKey.OP_ACCEPT); //注册 OP_ACCEPT事件  
    		 
    			while(true)     
    			   {     
    			    try     
    			    {     
    			     selector.select();     
    			     Set<SelectionKey> keys = selector.selectedKeys();     
    			     Iterator<SelectionKey> iter = keys.iterator();     
    			     SocketChannel sc = null ; 
    			     while(iter.hasNext())     
    			     {    
    			    	  
	    			   key = iter.next();
	    			   // 新的连接
	    			   if(key.isAcceptable()){
	    	                     // 调用accept方法接受连接,产生服务器端对应的SocketChannel  
	    	                     sc = serverChannel.accept();  
	    	                     // 设置采用非阻塞模式  
	    	                     sc.configureBlocking(false);  
	    	                     // 将该SocketChannel也注册到selector  
	    	                     sc.register(selector, SelectionKey.OP_READ | SelectionKey.OP_WRITE);  
	    	                     // 将sk对应的Channel设置成准备接受其他请求  
	    	                     key.interestOps(SelectionKey.OP_ACCEPT); 
	    			    }
	    			      
	    			    // 可读   
				    if(key.isReadable()) {
							
				       // 获取该SelectionKey对应的Channel,该Channel中有可读的数据  
                                       sc = (SocketChannel) key.channel();  
				       // 定义准备执行读取数据的ByteBuffer  
				       ByteBuffer buff = ByteBuffer.allocate(1024);  
				       String content = "";  
				       try {  
				          while (sc.read(buff) > 0) {  
					      buff.flip();  
					      content += charset.decode(buff);  
					      if (content!=null)
					      {
						 System.out.println("From Server: " + content);
						 //显示
						 String temp = textview_show.getText().toString();
						 mHandler.sendMessage(mHandler.obtainMessage(0, content + "\n" + temp));
//				            	 textview_show.setText(content + "\n" + textview_show.getText());
				                 ctmp =preferences.getString("zfdk", "");
										
						 try{
						      htmp = content;
						 }catch(Exception e) {
					         System.out.println("S: Error");
						 e.printStackTrace();          
					       }	
					 }
							            
				       }
				       // 将sk对应的Channel设置成准备下一次读取  
				       key.interestOps(SelectionKey.OP_READ);  
					}  
							    catch (IOException ex) {  
							        // 从Selector中删除指定的SelectionKey  
							    	key.cancel();  
							        if (key.channel() != null) {  
							        	key.channel().close();  
							        }  
							    }  
	
	    			      }
						  // 可写   
	    			      if (key.isWritable()) {
//	    			    	  String name = (String) key.attachment();
	    			    	  ByteBuffer block = encoder.encode(CharBuffer.wrap("from client!"));
	    			    	  System.out.println("发送成功! ");
	    			    	  sc.write(block);
//	    			    	  sc.write(ByteBuffer.wrap(new String("from client!").getBytes()));
	    			  
	    			      }
    			     } 
    			       iter.remove(); //处理完事件的要从keys中删去        
    			    }
    			    catch (Exception e)     
    			    {     
    			     e.printStackTrace();     
    			    }  
    			    
    			    
    			   } 
    			
    			
    	        }catch(Exception e) {
    	         System.out.println("S: Error");
    	            e.printStackTrace();          
    	        }
    	}
    }
	
	public static String str2HexStr(String str)    
	{      
	  
	    char[] chars = "0123456789ABCDEF".toCharArray();      
	    StringBuilder sb = new StringBuilder("");    
	    byte[] bs = str.getBytes();      
	    int bit;      
	        
	    for (int i = 0; i < bs.length; i++)    
	    {      
	        bit = (bs[i] & 0x0f0) >> 4;      
	        sb.append(chars[bit]);      
	        bit = bs[i] & 0x0f;      
	        sb.append(chars[bit]);    
	        sb.append(' ');    
	    }      
	    return sb.toString().trim();      
	}
	
	public static ByteBuffer getByteBuffer(String str)
    {
        return ByteBuffer.wrap(str.getBytes());
    }

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值