非阻塞socket实现android手机与PC的文件传输

来源:互联网 发布:中国大学生消费大数据 编辑:程序博客网 时间:2024/05/22 13:19

      项目需要是通过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() {@Overridepublic void onClick(View arg0) {// TODO Auto-generated method stubstring = et.getText().toString();new Thread(new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubSocketChannel 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的,讲得很好。

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


0 0