Alljoyn是高通开发的一个开源的p2p通信框架,支持wifi/蓝牙和wifi-direct。目前已经有了很多基于这个框架开发的联机游戏。
在Alljoyn的sdk里有很多例子,其中有一个通过raw session发送信息的,对这个例子略加修改就可以实现两个手机之间文件的传输。
在client端,其发送的信息是通过一个FileOutputStream将要发送的信息写入到一个中间文件来发送到对方的。所以我们只要将要发送的文件通过流的形式输入到这个FileOutputStream中就可以了。
- if (mStreamUp == true) {
- String string = (String) msg.obj + "\n";
- try {
- // logInfo(String.format("Writing %s to output stream",
- // string));
- // mOutputStream.write(string.getBytes());
- // logInfo(String.format("Flushing stream", string));
- // mOutputStream.flush();
- String filepath = "/sdcard/test.txt";
- File file = new File(filepath);
- InputStream in =new FileInputStream(file);
- byte[] buffer = new byte[1024];
- int read;
- long total = 0;
- while ((read = in.read(buffer)) != -1) {
- mOutputStream.write(buffer, 0, read);
- total+=read;
- Log.d("test","total:"+total);
- if(total>100000){
- mOutputStream.flush();
- total=0;
- //容易出现io exception,所以稍微等待一下。
- Thread.sleep(100);
- }
- }
- mOutputStream.flush();
- Log.d("test","flush");
- in.close();
- } catch (IOException ex) {
- Log.e("test",ex.toString());
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- break;
- }
其中前面注释掉的代码是实例程序原来的,下面的就是我修改的,将文件输入到输出流中。需要注意的是如果不加中间的sleep的话就会报IO Exception,这是因为raw使用的是非阻塞式socket发送的,如果发送得过快而网络传输得慢就会产生异常,中断传输。就好像一个大水池,一个水管往里注水,一个水管往外放水,如果注水的速度大于放水的速度的话水池就会溢出。所以在写入的时候稍微睡眠一下,也就是稍微控制一下注入的速度,让底层把内容发出去。
虽然这样可以在一定程度上减少异常的发生,但是传输的文件如果太大的话还是容易产生异常的,在这种情况下可以使用try catch来捕获这个异常然后休眠一段时间从中断的位置重新传输。
在server端,我们只需要将接受到的流写入到一个新建的文件中就可以了。其中注释掉的也是其原来的程序。
- mReader = new Thread(new Runnable() {
- public void run() {
- logInfo("Thread running");
- Looper.myLooper().prepare();
- StringBuilder stringBuilder = new StringBuilder();
- try {
- while (true) {
- int c;
- /*
- * Wait until a character is available.
- */
- if (reader.ready() == false) {
- Thread.sleep(100);
- continue;
- }
-
- /*
- * Build a string out of the characters and
- * when we see a newline, cook up a toast
- * do display them.
- */
- if(saveFile("/mnt/sdcard/test.txt",is)){
- Toast.makeText(Service.this, "save success", Toast.LENGTH_LONG).show();
- }else{
- Toast.makeText(Service.this, "save faild", Toast.LENGTH_LONG).show();
- }
- // try {
- // c = reader.read();
- // logInfo(String.format("Read %d from stream", c));
- // stringBuilder.append((char)c);
- // if (c == 10) {
- // String s = stringBuilder.toString();
- // logInfo(String.format("Read %s from stream", s));
- // Message toastMsg = mHandler.obtainMessage(MESSAGE_POST_TOAST, s);
- // mHandler.sendMessage(toastMsg);
- // stringBuilder.delete(0, stringBuilder.length() - 1);
- // }
- // } catch (IOException ex) {
- // }
- }
- } catch (Throwable ex) {
- logInfo(String.format("Exception reading raw Java stream: %s", ex.toString()));
- }
- logInfo("Thread exiting");
- }
- }, "reader");
- mReader.start();
我们还需要加入一个保存文件的函数:
- private static boolean saveFile(String filePath, InputStream is) {
- boolean saved = false;
- byte[] buffer = new byte[1024];
- FileOutputStream fos = null;
- File file = null;
- try {
- try {
- file = new File(filePath);
- fos = new FileOutputStream(file,true);
- } catch (Exception e) {
- Log.e(TAG,"creat file error");
- }
- int readlen = -1;
- long readCount = 0;
- while (true) {
- saved = true;
- try {
- readlen = is.read(buffer);
- } catch (IOException e) {
- Log.e(TAG,"read inputstream error");
- } finally {
- if (readlen <= 0) {
- break;
- }
- }
- readCount += readlen;
- Log.d("test","FILE length::::::::::::::::::::"+readCount);
- try {
- fos.write(buffer, 0, readlen);
- } catch (IOException e) {
- Log.e(TAG,"write file error");
- }
- }
- } finally {
- if (fos != null) {
- try {
- fos.close();
- } catch (IOException e) {
- Log.e(TAG, e.toString());
- }
- }
- fos = null;
- }
- Log.d("test","saved:"+saved);
- return saved;
- }
好了,这样在client端的sd卡的根目录中新建一个test.txt文件,当两个手机连接起来后,client端随便发送一个字符串就可以触发传输文件的操作了。
阅读(5607) | 评论(0) | 转发(1) |