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

    
  • 相关阅读:
    mysql修改数据库的存储引擎(InnoDB)
    如何查看进程/服务是否启动
    Spark Streaming 入门
    Graphlab create的基本使用
    构建房屋预测回归模型
    构建应用深层特征的图像检索系统
    构建商品评价的分类器
    Elastic Static初识(01)
    《Linux就该这么学》笔记(二)
    《Linux就该这么学》笔记(一)
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5315115.html
Copyright © 2011-2022 走看看