zoukankan      html  css  js  c++  java
  • 非堵塞socket实现android手机与PC的文件传输

          项目须要是通过WIFI建立手机和PC的通信,然后自己定义一个简单的协议对要传输的文件进行校验,传输的文件是2张3M的图片,要求考虑网络中断情况处理。

          我这里採用的是非堵塞socket来实现的,之前查过非常多资料,认为这样的比較方便,其有用传统的那种socket也是能够实现的,至于堵塞问题,能够开两个线程。这样保证读取不是同一个线程,也就能够解决。

          程序大致是这种流程,手机端发送一个“filename”字符串给PC,PC校验字符串后返回文件名称。然后手机端再把接收到的文件名称发送给PC端。进行校验,假设PC端校验成功,那么PC端就開始传输这个文件给手机端。手机端就接收这个文件。

    至于网络中断的问题,后来发现,仅仅要在服务端发送文件的那一段程序加入try-catch,捕获这个异常,这样服务端的程序就不会死掉,进入等待。等到手机再次和PC端建立连接。那么就能够又一次发送文件。这里是重传,而不是续传,后来想过。也仅仅有6M,实际測试过。大概2-3秒就能够传完。重传和续传意义不大,所以就简单的重传了。

          程序例如以下:

    PC端:

    public class MyServer {
    	private final static Logger logger = Logger.getLogger(MyServer.class.getName());
    	
    	public static void main(String[] args) {
    		Selector selector = null;
    		ServerSocketChannel serverSocketChannel = null;
    		
    		try {
    			selector = Selector.open();
    			serverSocketChannel = ServerSocketChannel.open();
    			serverSocketChannel.configureBlocking(false);
    			serverSocketChannel.socket().setReuseAddress(true);
    			serverSocketChannel.socket().bind(new InetSocketAddress(1991));
    			serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);
    			while (selector.select() > 0) {
    				Iterator<SelectionKey> it = selector.selectedKeys().iterator();
    				while (it.hasNext()) {
    					SelectionKey readyKey = it.next();
    					it.remove();
    
    					SocketChannel socketChannel = null;
    					String string = "";
    					try {
    						socketChannel = ((ServerSocketChannel) readyKey.channel()).accept();
    						string = receiveData(socketChannel);
    						logger.log(Level.INFO, string);
    						if(string.equals("filename")){
    							File f= new File("D:/chz.jpg");  
    						    if (f.exists() && f.isFile()){  
    						        sendData(socketChannel, "chz.jpg");
    						    }else{  
    						        logger.info("file doesn't exist or is not a file");  
    						    }  
    						}
    						if(string.equals("chz.jpg")){
    							sendFile(socketChannel, new File("D:/chz.jpg"));
    						}
    					}catch(Exception ex){
    						logger.log(Level.SEVERE, "1", ex);
    					} finally {
    						try {
    							socketChannel.close();
    						} catch(Exception ex) {
    							logger.log(Level.SEVERE, "2", ex);
    						}
    					}
    				}
    			}
    		} catch (ClosedChannelException ex) {
    			logger.log(Level.SEVERE, "3", ex);
    		} catch (IOException ex) {
    			logger.log(Level.SEVERE, "4", ex);
    		} finally {
    			try {
    				selector.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "5", ex);
    			}
    			try {
    				serverSocketChannel.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "6", ex);
    			}
    		}
    	}
    
    	private static String receiveData(SocketChannel socketChannel) throws IOException {
    		String string = null;
    		ByteArrayOutputStream baos = new ByteArrayOutputStream();
    		ByteBuffer buffer = ByteBuffer.allocate(1024);
    		
    		try {
    			byte[] bytes;
    			int size = 0;
    			while ((size = socketChannel.read(buffer)) >= 0) {
    				buffer.flip();
    				bytes = new byte[size];
    				buffer.get(bytes);
    				baos.write(bytes);
    				buffer.clear();
    			}
    			bytes = baos.toByteArray();
    			string = new String(bytes);
    		}catch(Exception ex){
    			logger.log(Level.SEVERE, "7", ex);
    		}finally {
    			try {
    				baos.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "8", ex);
    			}
    		}
    		return string;
    	}
    
    	private static void sendData(SocketChannel socketChannel, String string) throws IOException {
    		byte[] bytes = string.getBytes();
    		ByteBuffer buffer = ByteBuffer.wrap(bytes);
    		socketChannel.write(buffer);
    		socketChannel.socket().shutdownOutput();
    	}
    	
    	private static void receiveFile(SocketChannel socketChannel, File file) throws IOException {
    		FileOutputStream fos = null;
    		FileChannel channel = null;
    		
    		try {
    			fos = new FileOutputStream(file);
    			channel = fos.getChannel();
    			ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
    
    			int size = 0;
    			while ((size = socketChannel.read(buffer)) != -1) {
    				buffer.flip();
    				if (size > 0) {
    					buffer.limit(size);
    					channel.write(buffer);
    					buffer.clear();
    				}
    			}
    		}catch(Exception ex){
    			logger.log(Level.SEVERE, "9", ex);
    		} finally {
    			try {
    				channel.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "10", ex);
    			}
    			try {
    				fos.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "11", ex);
    			}
    		}
    	}
    
    	private static void sendFile(SocketChannel socketChannel, File file) throws IOException {
    		FileInputStream fis = null;
    		FileChannel channel = null;
    		try {
    			fis = new FileInputStream(file);
    			channel = fis.getChannel();
    			ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
    			int size = 0;
    			while ((size = channel.read(buffer)) != -1) {
    				buffer.rewind();
    				buffer.limit(size);
    				socketChannel.write(buffer);
    				buffer.clear();
    			}
    			socketChannel.socket().shutdownOutput();
    		}catch(Exception ex){
    			logger.log(Level.SEVERE, "12", ex);
    		} finally {
    			try {
    				channel.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "13", ex);
    			}
    			try {
    				fis.close();
    			} catch(Exception ex) {
    				logger.log(Level.SEVERE, "14", ex);
    			}
    		}
    	}
    }

    ANDROID端:

    public class MainActivity extends Activity {
    
    	private Button mButton;
    	private EditText et;
    	private static String string;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
         
            et = (EditText)findViewById(R.id.edittext1);
            et.setText("192.168.1.214");
    		mButton = (Button)findViewById(R.id.button1);
    		mButton.setOnClickListener(new OnClickListener() {
    			
    			@Override
    			public void onClick(View arg0) {
    				// TODO Auto-generated method stub
    				string = et.getText().toString();
    				new Thread(new Runnable() {
    					
    					@Override
    					public void run() {
    						// TODO Auto-generated method stub
    						SocketChannel socketChannel = null;
    						try {
    							socketChannel = SocketChannel.open();
    							SocketAddress socketAddress = new InetSocketAddress(string, 1991);
    							socketChannel.connect(socketAddress);
    							
    							sendData(socketChannel, "filename");
    							String string = "";
    							string = receiveData(socketChannel);
    							if(!string.isEmpty()){
    								socketChannel = SocketChannel.open();
    								socketChannel.connect(new InetSocketAddress("192.168.1.214", 1991));
    								sendData(socketChannel, string);
    								receiveFile(socketChannel, new File("sdcard/afile/"+string));
    							}
    						} catch (Exception ex) {
    							Log.i("chz", null, ex);
    						} finally {
    							try {
    								socketChannel.close();
    							} catch(Exception ex) {}
    						}
    					}
    				}).start();
    			}
    		});
    	
       }
    
    		private void sendData(SocketChannel socketChannel, String string) throws IOException {
    			byte[] bytes = string.getBytes();
    			ByteBuffer buffer = ByteBuffer.wrap(bytes);
    			socketChannel.write(buffer);
    			socketChannel.socket().shutdownOutput();
    		}
    
    		private String receiveData(SocketChannel socketChannel) throws IOException {
    			String string = null;
    			ByteArrayOutputStream baos = new ByteArrayOutputStream();
    			
    			try {
    				ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
    				byte[] bytes;
    				int count = 0;
    				while ((count = socketChannel.read(buffer)) >= 0) {
    					buffer.flip();
    					bytes = new byte[count];
    					buffer.get(bytes);
    					baos.write(bytes);
    					buffer.clear();
    				}
    				bytes = baos.toByteArray();
    				string = new String(bytes);
    //				socketChannel.socket().shutdownInput();
    			} finally {
    				try {
    					baos.close();
    				} catch(Exception ex) {}
    			}
    			return string;
    		}
    		
    		private static void sendFile(SocketChannel socketChannel, File file) throws IOException {
    			FileInputStream fis = null;
    			FileChannel channel = null;
    			try {
    				fis = new FileInputStream(file);
    				channel = fis.getChannel();
    				ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
    				int size = 0;
    				while ((size = channel.read(buffer)) != -1) {
    					buffer.rewind();
    					buffer.limit(size);
    					socketChannel.write(buffer);
    					buffer.clear();
    				}
    				socketChannel.socket().shutdownOutput();
    			} finally {
    				try {
    					channel.close();
    				} catch(Exception ex) {}
    				try {
    					fis.close();
    				} catch(Exception ex) {}
    			}
    		}
    
    		private static void receiveFile(SocketChannel socketChannel, File file) throws IOException {
    			FileOutputStream fos = null;
    			FileChannel channel = null;
    			
    			try {
    				fos = new FileOutputStream(file);
    				channel = fos.getChannel();
    				ByteBuffer buffer = ByteBuffer.allocateDirect(1024);
    
    				int size = 0;
    				while ((size = socketChannel.read(buffer)) != -1) {
    					buffer.flip();
    					if (size > 0) {
    						buffer.limit(size);
    						channel.write(buffer);
    						buffer.clear();
    					}
    				}
    			} finally {
    				try {
    					channel.close();
    				} catch(Exception ex) {}
    				try {
    					fos.close();
    				} catch(Exception ex) {}
    			}
    		}
    
    
        @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;
        }
    
        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            // Handle action bar item clicks here. The action bar will
            // automatically handle clicks on the Home/Up button, so long
            // as you specify a parent activity in AndroidManifest.xml.
            int id = item.getItemId();
            if (id == R.id.action_settings) {
                return true;
            }
            return super.onOptionsItemSelected(item);
        }
    }
    

          番外:事实上做这个文件传输遇到的最头痛的问题不是程序难不难写。而是wifi通信的建立。最初我是用自己win7的电脑连路由器。然后手机也连路由器做的測试,没有问题。但是后来项目需求是下位机是一台XP的电脑。并且要求点对点建立wifi,所以仅仅能有一端设成wifi热点。还有一端连接这个热点。设想非常完美,然后找了实验室唯一一台XP电脑測试了两天,都没有可以让我手机连上PC。后来各种问,才知道XP不支持为android创wifi热点,真心坑呀。然后我就想反过来做呗,手机建wifi热点,电脑连。耶果然连上了,但是。明明写好的程序,各种执行不了,最后手机巨热,(我心痛死我的小米。求不黑小米。真心一直用小米,仅仅是导师不给配开发手机,仅仅能用自己手机,哎)所以直接pass这个想法,最后百度了一下。貌似可以接外接硬件设备,例如说360随身wifi硬件,嗯导师最终答应淘宝买一个来測试下,今天买吧。

           哦,整个程序參考了两位大神博客:http://www.cnblogs.com/hongten/archive/2012/04/29/java_socket.html

     http://blog.csdn.net/kongxx/article/details/7288896尤其是后面这位大神的一个专栏专门讲java socket的。讲得非常好。

          这个文件传输的整个project地址:http://download.csdn.net/detail/u012321815/8047863

    
  • 相关阅读:
    PDF文件中的Form保存问题
    Understanding IP Fragmentation
    tcp ip guide IPsec IKE
    Windows安全事件日志中的事件编号与描述
    Cisco PIX fix up and Juniper firewall FTP ALG
    很好的IPSec介绍,详细解释了IKE协商的2个阶段的作用
    virtualbox 下运行Ubuntu 8.10的分辨率和guest additions的问题。
    Fixing the ‘Do you want to display nonsecure items’ message
    windows xp 开始菜单里面所有项目右键不起作用。
    HP backup and recovery manager
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5315115.html
Copyright © 2011-2022 走看看