无网络传输android

  • 首页
  • 博客
  • 学院
  • 下载
  • GitChat
  • TinyMind
  • 论坛
  • 问答
  • 商城
  • VIP
  • 活动
  • 招聘
  • ITeye
  • CSTO
郭霖

Android技术分享平台,每天都有优质技术文章推送.你还可以向公众号投稿,将自己总结的技术心得分享给大家....

RSS订阅
点对点文件传输,Android无网络传输文件的原理



今日科技快讯


昨日,上海交通执法部门在虹桥机场、虹桥火车站等共14个执法点开展了代号为“天网2号”的网约车非法客运专项整治行动。当天行动累计查处利用网约平台从事非法客运的案件37件,其中“滴滴”29件,“美团”6件,“神州”1件,“嘀嗒”1件。这些车辆及驾驶员均无营运资质,他们通过自己在网约平台软件上的注册账号接单,将乘客送至目的地,并收取车费。


作者简介


明天就是清明小长假了,希望大家都能好好享受这几天的假期时光,我们清明节后见!

本篇来自  叶应是叶 的投稿,分享了Android 实现无网络传输文件,一起来看看!希望大家喜欢。

 叶应是叶  的博客地址:

https://www.jianshu.com/u/9df45b87cfdf


正文


最近的项目需要实现一个Android手机之间无网络传输文件的功能,就发现了Wifi P2P(Wifi点对点)这么一个功能,最后也实现了通过Wifi 隔空传输文件的功能,这里我也来整理下代码,分享给大家。

Wifi P2P是在Android 4.0以及更高版本系统中加入的功能,通过Wifi P2P可以在不连接网络的情况下,直接与配对的设备进行数据交换。相对于蓝牙,Wifi P2P的搜索速度和传输速度更快,传输距离更远

实现的效果如下所示:

无网络传输android_第1张图片

无网络传输android_第2张图片

一般而言,开发步骤分为以下几点:

  • 在AndroidManifest中声明相关权限(网络和文件读写权限)

  • 获取WifiP2pManager,注册相关广播监听Wifi直连的状态变化

  • 指定某一台设备为服务器(用来接收文件),创建群组并作为群主存在,在指定端口监听客户端的连接请求,等待客户端发起连接请求以及文件传输请求

  • 客户端(用来发送文件)主动搜索附近的设备,加入到服务器创建的群组,获取服务器的IP地址,向其发起文件传输请求

  • 校验文件完整性

声明权限

Wifi P2P技术并不访问网络,但由于会使用到Java套接字,所以需要申请网络权限。此外,由于是要实现文件互传,所以也需要申请SD卡读写权限。

"android.permission.ACCESS_WIFI_STATE" />
   "android.permission.CHANGE_WIFI_STATE" />
   "android.permission.CHANGE_NETWORK_STATE" />
   "android.permission.INTERNET" />
   "android.permission.ACCESS_NETWORK_STATE" />
   "android.permission.WRITE_EXTERNAL_STORAGE" />
   "android.permission.READ_EXTERNAL_STORAGE" />

注册广播

与Wifi P2P相关的广播有以下几个:

  1. WIFI_P2P_STATE_CHANGED_ACTION(用于指示Wifi P2P是否可用)

  2. WIFI_P2P_PEERS_CHANGED_ACTION(对等节点列表发生了变化)

  3. WIFI_P2P_CONNECTION_CHANGED_ACTION(Wifi P2P的连接状态发生了改变)

  4. WIFI_P2P_THIS_DEVICE_CHANGED_ACTION(本设备的设备信息发生了变化)

当接收到这几个广播时,我们都需要到WifiP2pManager(对等网络管理器)来进行相应的信息请求,此外还需要用到Channel对象作为请求参数

mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);

当收到WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION广播时,可以判断当前Wifi P2P是否可用

int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
   mDirectActionListener.wifiP2pEnabled(true);
} else {
   mDirectActionListener.wifiP2pEnabled(false);                
}

当收到WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION广播时,意味设备周围的可用设备列表发生了变化,可以通过requestPeers方法得到可用的设备列表,之后就可以选择当中的某一个设备进行连接操作

mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
   @Override
   public void onPeersAvailable(WifiP2pDeviceList peers) {
       mDirectActionListener.onPeersAvailable(peers.getDeviceList());
   }
});

当收到WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION广播时,意味着Wifi P2P的连接状态发生了变化,可能是连接到了某设备,或者是与某设备断开了连接

NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
   mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
       @Override
       public void onConnectionInfoAvailable(WifiP2pInfo info) {
           mDirectActionListener.onConnectionInfoAvailable(info);
       }
   });
   Log.e(TAG, "已连接p2p设备");
} else {
   mDirectActionListener.onDisconnection();
   Log.e(TAG, "与p2p设备已断开连接");
}

如果是与某设备连接上了,则可以通过requestConnectionInfo方法获取到连接信息。

当收到WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION广播时,则可以获取到本设备变化后的设备信息

(WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)

可以看出Wifi P2P的接口高度异步化,到现在已经用到了三个系统的回调函数,一个用于WifiP2pManager的初始化,两个用于在广播中异步请求数据,为了简化操作,此处统一使用一个自定义的回调函数,方法含义与系统的回调函数一致

public interface DirectActionListener extends WifiP2pManager.ChannelListener {

   void wifiP2pEnabled(boolean enabled);

   void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);

   void onDisconnection();

   void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice);

   void onPeersAvailable(Collection wifiP2pDeviceList);

}

所以,整个广播接收器使用到的所有代码是:

/**
* 作者:chenZY
* 时间:2018/2/9 17:53
* 描述:
*/

public class DirectBroadcastReceiver extends BroadcastReceiver {

   private static final String TAG = "DirectBroadcastReceiver";

   private WifiP2pManager mWifiP2pManager;

   private WifiP2pManager.Channel mChannel;

   private DirectActionListener mDirectActionListener;

   public DirectBroadcastReceiver(WifiP2pManager wifiP2pManager, WifiP2pManager.Channel channel, DirectActionListener directActionListener) {
       mWifiP2pManager = wifiP2pManager;
       mChannel = channel;
       mDirectActionListener = directActionListener;
   }

   public static IntentFilter getIntentFilter() {
       IntentFilter intentFilter = new IntentFilter();
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
       intentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);
       return intentFilter;
   }

   @Override
   public void onReceive(Context context, Intent intent) {
       Log.e(TAG, "接收到广播: " + intent.getAction());
       if (!TextUtils.isEmpty(intent.getAction())) {
           switch (intent.getAction()) {
               // 用于指示 Wifi P2P 是否可用
               case WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION: {
                   int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
                   if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                       mDirectActionListener.wifiP2pEnabled(true);
                   } else {
                       mDirectActionListener.wifiP2pEnabled(false);
                       List wifiP2pDeviceList = new ArrayList<>();
                       mDirectActionListener.onPeersAvailable(wifiP2pDeviceList);
                   }
                   break;
               }
               // 对等节点列表发生了变化
               case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION: {
                   mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
                       @Override
                       public void onPeersAvailable(WifiP2pDeviceList peers) {
                           mDirectActionListener.onPeersAvailable(peers.getDeviceList());
                       }
                   });
                   break;
               }
               // Wifi P2P 的连接状态发生了改变
               case WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION: {
                   NetworkInfo networkInfo = intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
                   if (networkInfo.isConnected()) {
                       mWifiP2pManager.requestConnectionInfo(mChannel, new WifiP2pManager.ConnectionInfoListener() {
                           @Override
                           public void onConnectionInfoAvailable(WifiP2pInfo info) {
                               mDirectActionListener.onConnectionInfoAvailable(info);
                           }
                       });
                       Log.e(TAG, "已连接p2p设备");
                   } else {
                       mDirectActionListener.onDisconnection();
                       Log.e(TAG, "与p2p设备已断开连接");
                   }
                   break;
               }
               //本设备的设备信息发生了变化
               case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: {
                   mDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
                   break;
               }
           }
       }
   }

}

服务器端创建群组

假设当设备甲搜索到了设备B,并与设备乙连接到了一起,此时系统会自动创建一个群组(集团)并随机指定一台设备为群主(GroupOwner)。此时,对于两台设备来说,群主的IP地址是可知的(系统回调函数中有提供),但客户端的IP地址需要再来通过其他方法来主动获取。例如,可以在设备连接成功后,客户端主动发起对服务器端的插座连接请求,服务器端在指定端口监听客户端的连接请求,当连接成功后,服务器端就可以获取到客户端的IP地址了。此处为了简化操作,直接指定某台设备作为服务器端(群主),即直接指定某台设备用来接收文件。因此,服务器端要主动创建群组,并等待客户端的连接。

wifiP2pManager.createGroup(channel, new WifiP2pManager.ActionListener() {
   @Override
   public void onSuccess() {
       Log.e(TAG, "createGroup onSuccess");
       dismissLoadingDialog();
       showToast("onSuccess");
   }

    @Override
    public void onFailure(int reason) {
       Log.e(TAG, "createGroup onFailure: " + reason);
       dismissLoadingDialog();
       showToast("onFailure");
   }
});

此处,使用IntentService在后台监听客户端的Socket连接请求,并通过输入输出流来传输文件。此处的代码比较简单,就是在指定端口一直堵塞监听客户端的连接请求,获取待传输的文件信息模型FileTransfer,之后就进行实际的数据传输

@Override
   protected void onHandleIntent(Intent intent) {
       clean();
       File file = null;
       try {
           serverSocket = new ServerSocket();
           serverSocket.setReuseAddress(true);
           serverSocket.bind(new InetSocketAddress(PORT));
           Socket client = serverSocket.accept();
           Log.e(TAG, "客户端IP地址 : " + client.getInetAddress().getHostAddress());
           inputStream = client.getInputStream();
           objectInputStream = new ObjectInputStream(inputStream);
           FileTransfer fileTransfer = (FileTransfer) objectInputStream.readObject();
           Log.e(TAG, "待接收的文件: " + fileTransfer);
           String name = new File(fileTransfer.getFilePath()).getName();
           //将文件存储至指定位置
           file = new File(Environment.getExternalStorageDirectory() + "/" + name);
           fileOutputStream = new FileOutputStream(file);
           byte buf[] = new byte[512];
           int len;
           long total = 0;
           int progress;
           while ((len = inputStream.read(buf)) != -1) {
               fileOutputStream.write(buf, 0, len);
               total += len;
               progress = (int) ((total * 100) / fileTransfer.getFileLength());
               Log.e(TAG, "文件接收进度: " + progress);
               if (progressChangListener != null) {
                   progressChangListener.onProgressChanged(fileTransfer, progress);
               }
           }
           serverSocket.close();
           inputStream.close();
           objectInputStream.close();
           fileOutputStream.close();
           serverSocket = null;
           inputStream = null;
           objectInputStream = null;
           fileOutputStream = null;
           Log.e(TAG, "文件接收成功,文件的MD5码是:" + Md5Util.getMd5(file));
       } catch (Exception e) {
           Log.e(TAG, "文件接收 Exception: " + e.getMessage());
       } finally {
           clean();
           if (progressChangListener != null) {
               progressChangListener.onTransferFinished(file);
           }
           //再次启动服务,等待客户端下次连接
           startService(new Intent(this, WifiServerService.class));
       }
   }

因为客户端可能会多次发起连接请求,所以当此处理文件传输完成后(不管成功或失败),都需要重新startService,让服务再次堵塞等待客户端的连接请求。

FileTransfer包含三个字段,MD5码值用于校验文件的完整性,fileLength是为了用于计算文件的传输进度。

public class FileTransfer implements Serializable {

   //文件路径
   private String filePath;

   //文件大小
   private long fileLength;

   //MD5码
   private String md5;

   ···

}

为了将文件传输进度发布到外部界面,所以除了需要启动服务外,界面还需要绑定服务,此处就需要用到一个更新文件传输状态的接口。

public interface OnProgressChangListener {

       //当传输进度发生变化时
       void onProgressChanged(FileTransfer fileTransfer, int progress);

       //当传输结束时
       void onTransferFinished(File file);

   }

因此,需要将progressChangListener作为参数传给WifiServerService,并在进度变化时更新进度对话框。

private WifiServerService.OnProgressChangListener progressChangListener = new WifiServerService.OnProgressChangListener() {
       @Override
       public void onProgressChanged(final FileTransfer fileTransfer, final int progress) {
           runOnUiThread(new Runnable() {
               @Override
               public void run() {
                   progressDialog.setMessage("文件名: " + new File(fileTransfer.getFilePath()).getName());
                   progressDialog.setProgress(progress);
                   progressDialog.show();
               }
           });
       }

       @Override
       public void onTransferFinished(final File file) {
           runOnUiThread(new Runnable() {
               @Override
               public void run() {
                   progressDialog.cancel();
                   if (file != null && file.exists()) {
                       openFile(file.getPath());
                   }
               }
           });
       }
   };

客户端加入群组并发起文件传输请求

文件发送界面SendFileActivity需要实现DirectActionListener接口首先,需要先注册P2P广播,以便获取周边设备信息以及连接状态

@Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_send_file);
       initView();
       mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
       mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);
       broadcastReceiver = new DirectBroadcastReceiver(mWifiP2pManager, mChannel, this);
       registerReceiver(broadcastReceiver, DirectBroadcastReceiver.getIntentFilter());
   }

通过discoverPeers方法搜索周边设备,回调函数用于通知方法是否调用成功。

mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() {
   @Override
   public void onSuccess() {
       showToast("Success");
   }

   @Override
   public void onFailure(int reasonCode) {
       showToast("Failure");
       loadingDialog.cancel();
    }
});

当搜索结束后,系统就会触发WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION广播,此时就可以调用requestPeers方法获取设备列表信息,此处用RecyclerView展示列表,在onPeersAvailable方法刷新列表。

mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
   @Override
   public void onPeersAvailable(WifiP2pDeviceList peers) {
       mDirectActionListener.onPeersAvailable(peers.getDeviceList());
   }
});
@Override
   public void onPeersAvailable(Collection wifiP2pDeviceList) {
       Log.e(TAG, "onPeersAvailable :" + wifiP2pDeviceList.size());
       this.wifiP2pDeviceList.clear();
       this.wifiP2pDeviceList.addAll(wifiP2pDeviceList);
       deviceAdapter.notifyDataSetChanged();
       loadingDialog.cancel();
   }

之后,通过点击事件选中群主(服务器端)设备,通过连接方法请求与之进行连接

private void connect() {
   WifiP2pConfig config = new WifiP2pConfig();
   if (config.deviceAddress != null && mWifiP2pDevice != null) {
       config.deviceAddress = mWifiP2pDevice.deviceAddress;
       config.wps.setup = WpsInfo.PBC;
       showLoadingDialog("正在连接 " + mWifiP2pDevice.deviceName);
       mWifiP2pManager.connect(mChannel, config, new WifiP2pManager.ActionListener() {
           @Override
           public void onSuccess() {
               Log.e(TAG, "connect onSuccess");
           }

           @Override
           public void onFailure(int reason) {
               showToast("连接失败 " + reason);
               dismissLoadingDialog();
           }
       });
   }
}

此处依然无法通过函数函数来判断连接结果,需要依靠系统发出的WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION   方法来获取到连接结果,在此处可以通过requestConnectionInfo获取到组连接信息,信息最后通过onConnectionInfoAvailable方法传递出来,在此可以判断当前设备是否为群主,获取群组IP地址。

@Override
public void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) {
   dismissLoadingDialog();
   wifiP2pDeviceList.clear();
   deviceAdapter.notifyDataSetChanged();
   btn_disconnect.setEnabled(true);
   btn_chooseFile.setEnabled(true);
   Log.e(TAG, "onConnectionInfoAvailable");
   Log.e(TAG, "onConnectionInfoAvailable groupFormed: " + wifiP2pInfo.groupFormed);
   Log.e(TAG, "onConnectionInfoAvailable isGroupOwner: " + wifiP2pInfo.isGroupOwner);
   Log.e(TAG, "onConnectionInfoAvailable getHostAddress: " + wifiP2pInfo.groupOwnerAddress.getHostAddress());
   StringBuilder stringBuilder = new StringBuilder();
   if (mWifiP2pDevice != null) {
       stringBuilder.append("连接的设备名:");
       stringBuilder.append(mWifiP2pDevice.deviceName);
       stringBuilder.append("\n");
       stringBuilder.append("连接的设备的地址:");
       stringBuilder.append(mWifiP2pDevice.deviceAddress);
   }
   stringBuilder.append("\n");
   stringBuilder.append("是否群主:");
   stringBuilder.append(wifiP2pInfo.isGroupOwner ? "是群主" : "非群主");
   stringBuilder.append("\n");
   stringBuilder.append("群主IP地址:");
   stringBuilder.append(wifiP2pInfo.groupOwnerAddress.getHostAddress());
   tv_status.setText(stringBuilder);
   if (wifiP2pInfo.groupFormed && !wifiP2pInfo.isGroupOwner) {
       this.wifiP2pInfo = wifiP2pInfo;
   }
}

至此服务器端和客户端已经通过Wifi P2P连接在了一起,客户端也获取到了服务器端的IP地址,在选取好待发送的文件后就可以主动发起对服务器端的连接请求了。

发起选取文件的方法

Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("*/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, 1);

获取选取的文件的实际路径

@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);
   if (requestCode == 1) {
       if (resultCode == RESULT_OK) {
           Uri uri = data.getData();
           if (uri != null) {
               String path = getPath(this, uri);
               if (path != null) {
                   File file = new File(path);
                   if (file.exists() && wifiP2pInfo != null) {
                       FileTransfer fileTransfer = new FileTransfer(file.getPath(), file.length());
                       Log.e(TAG, "待发送的文件:" + fileTransfer);
                       new WifiClientTask(this, fileTransfer).execute(wifiP2pInfo.groupOwnerAddress.getHostAddress());
                   }
               }
           }
       }
   }
}

private String getPath(Context context, Uri uri) {
   if ("content".equalsIgnoreCase(uri.getScheme())) {
       Cursor cursor = context.getContentResolver().query(uri, new String[]{"_data"}, null, null, null);
       if (cursor != null) {
          if (cursor.moveToFirst()) {
               String data = cursor.getString(cursor.getColumnIndex("_data"));
               cursor.close();
               return data;
           }
       }
   } else if ("file".equalsIgnoreCase(uri.getScheme())) {
       return uri.getPath();
   }
   return null;
}

文件的发送操作放到AsyncTask中处理,将服务器端的IP地址作为参数传进来,在正式发送文件前,先发送包含文件信息(文件名,文件大小,文件MD5码)的信息模型FileTransfer,并在发送文件的过程中同时更新进度

/**
* 作者:叶应是叶
* 时间:2018/2/15 8:51
* 描述:客户端发送文件
*/

public class WifiClientTask extends AsyncTask<String, Integer, Boolean> {

   private ProgressDialog progressDialog;

   private FileTransfer fileTransfer;

   private static final int PORT = 4786;

   private static final String TAG = "WifiClientTask";

   public WifiClientTask(Context context, FileTransfer fileTransfer) {
       this.fileTransfer = fileTransfer;
       progressDialog = new ProgressDialog(context);
       progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
       progressDialog.setCancelable(false);
       progressDialog.setCanceledOnTouchOutside(false);
       progressDialog.setTitle("正在发送文件");
       progressDialog.setMax(100);
   }

   @Override
   protected void onPreExecute() {
       progressDialog.show();
   }

   @Override
   protected Boolean doInBackground(String... strings) {
       fileTransfer.setMd5(Md5Util.getMd5(new File(fileTransfer.getFilePath())));
       Log.e(TAG, "文件的MD5码值是:" + fileTransfer.getMd5());
       Socket socket = null;
       OutputStream outputStream = null;
       ObjectOutputStream objectOutputStream = null;
       InputStream inputStream = null;
       try {
           socket = new Socket();
           socket.bind(null);
           socket.connect((new InetSocketAddress(strings[0], PORT)), 10000);
           outputStream = socket.getOutputStream();
           objectOutputStream = new ObjectOutputStream(outputStream);
           objectOutputStream.writeObject(fileTransfer);
           inputStream = new FileInputStream(new File(fileTransfer.getFilePath()));
           long fileSize = fileTransfer.getFileLength();
           long total = 0;
           byte buf[] = new byte[512];
           int len;
           while ((len = inputStream.read(buf)) != -1) {
               outputStream.write(buf, 0, len);
               total += len;
               int progress = (int) ((total * 100) / fileSize);
               publishProgress(progress);
               Log.e(TAG, "文件发送进度:" + progress);
           }
           outputStream.close();
           objectOutputStream.close();
           inputStream.close();
           socket.close();
           outputStream = null;
           objectOutputStream = null;
           inputStream = null;
           socket = null;
           Log.e(TAG, "文件发送成功");
           return true;
       } catch (Exception e) {
           Log.e(TAG, "文件发送异常 Exception: " + e.getMessage());
       } finally {
           if (outputStream != null) {
               try {
                   outputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           if (objectOutputStream != null) {
               try {
                   objectOutputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           if (inputStream != null) {
               try {
                   inputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
           if (socket != null) {
               try {
                   socket.close();
               } catch (Exception e) {
                   e.printStackTrace();
               }
           }
       }
       return false;
   }

   @Override
   protected void onProgressUpdate(Integer... values) {
       progressDialog.setProgress(values[0]);
   }

   @Override
   protected void onPostExecute(Boolean aBoolean) {
       progressDialog.cancel();
       Log.e(TAG, "onPostExecute: " + aBoolean);
   }

}

校验文件完整性

传输文件的完整性主要是通过计算文件的MD5码值来保证了,在发送文件前,即在WifiClientTask的doInBackground方法中进行计算,将MD5码值赋给给FileTransfer模型,通过如下方法计算得到

/**
* 作者:叶应是叶
* 时间:2018/2/14 21:16
* 描述:
*/

public class Md5Util {

   public static String getMd5(File file) {
       InputStream inputStream = null;
       byte[] buffer = new byte[2048];
       int numRead;
       MessageDigest md5;
       try {
           inputStream = new FileInputStream(file);
           md5 = MessageDigest.getInstance("MD5");
           while ((numRead = inputStream.read(buffer)) > 0) {
               md5.update(buffer, 0, numRead);
           }
           inputStream.close();
           inputStream = null;
           return md5ToString(md5.digest());
       } catch (Exception e) {
           return null;
       } finally {
           if (inputStream != null) {
               try {
                   inputStream.close();
               } catch (IOException e) {
                   e.printStackTrace();
               }
           }
       }
   }

   private static String md5ToString(byte[] md5Bytes) {
       StringBuilder hexValue = new StringBuilder();
       for (byte b : md5Bytes) {
           int val = ((int) b) & 0xff;
           if (val < 16) {
               hexValue.append("0");
           }
           hexValue.append(Integer.toHexString(val));
       }
       return hexValue.toString();
   }

}


总结


因为客户端会将FileTransfer传给服务器端,所以服务器端在文件传输结束后,可以重新计算文件的MD5码值,进行对比以判断文件是否完整。这里分享下上述代码,地址如下:

https://github.com/leavesC/WifiP2P


欢迎长按下图 -> 识别图中二维码

或者 扫一扫 关注我的公众号

android socket 点对点文件传输mode

2015年05月05日 49KB 下载

Android之间互相的录屏直播 --点对点传输(tcp长连接发送h264)(一)

前言 近期准备学习了一些流媒体的资料.因此找到了来疯直播这个开源项目,研究了段时间,对来疯的代码架构佩服的五体投地. 感谢来疯直播,先附上来疯直播的地址 于是在来疯直播的基础上,自己添加了一个利用tc...

baidu_33546245 baidu_33546245

2017-11-29 21:36:38

阅读数:2075

您有一张免费的北京车展门票等待领取美好购车节 · 顶新

android网络编程 -- Socket 通信(03) 点对点Android聊天室实现(带服务器) [附源码分析]

1-简介: 概念:在网络上的两个程序通过一个双向的通信连接实现数据的交换,这个双向链路的一端称为一个socket。 组成:由一个IP地址和一个端口号唯一确定,是TCP/IP 协议的一个十分流行的编程界...

hit_rxz hit_rxz

2014-09-20 18:12:18

阅读数:4288

使用Socket进行设备间点对点连接传输数据

对GCDAsyncSocket和GCDAsyncUdpSocket进行封装, 实现了服务器通过UDP广播向局域网发送数据, 客户端接收后与服务器进行TCP连接, 成功连接后进行点对点通信....

liangshi1 liangshi1

2016-06-04 15:55:57

阅读数:4424

Android网络传输文件之WifiP2P

    WifiP2P是在 Android 4.0 以上系统中加入的功能,通过WifiP2P可以在不连接网络的情况下,直接与配对的设备进行数据交换。他相比蓝牙传输速率更快,更远;相比网络传输过程中不会...

yoonerloop yoonerloop

2018-03-06 22:38:07

阅读数:453

Android 实现无网络传输文件(2)

在我的上一篇文章:Android 实现无网络传输文件,我介绍了通过 Wifi Direct(Wifi 直连)实现 Android 设备之间进行文件传输的方法,可以在无移动网络的情况下实现点对点文件传...

new_one_object new_one_object

2018-02-25 12:20:24

阅读数:281

2018北京高端会所体验!揭开高级会所神秘面纱!花韵会所 · 顶新

android wifi连接+基于socket的文件数据传输(上)

分客户端和服务器端两大部分介绍: 客户端: 1.WiFi连接: 1.1开启WiFi       public void openWifi () { if (!mWifiMa...

u011032983 u011032983

2016-06-27 22:06:35

阅读数:4713

Android 实现无网络传输文件

最近的项目需要实现一个 Android 手机之间无网络传输文件的功能,就发现了 Wifi P2P(Wifi点对点)这么一个功能,最后也实现了通过 Wifi 隔空传输文件的功能,这里我也来整理下代码,分...

new_one_object new_one_object

2018-02-16 00:43:38

阅读数:180

Android 如何实现无网络传输文件

点击上方“程序员大咖”,选择“置顶公众号”关键时刻,第一时间送达!最近的项目需要实现一个 Android 手机之间无网络传输文件的功能,就发现了 Wifi P2P(Wifi点对点)这么一个功能,最后也...

Px01Ih8 Px01Ih8

2018-03-29 00:00:00

阅读数:303

使用Socket进行设备间点对点连接传输数据

前言 最近在做一套点对点传输的软件, 需要用到Socket进行设备间通讯. 去网上查了查, 对Socket分装比较好的就是目前特别火的GCDAsyncSocket这个类了, 这篇文章就GDCAsyn...

args_ args_

2016-08-04 14:50:28

阅读数:1539

点对点文件上传下载软件.rar

简单的2人点对点聊天工具 立即下载 上传者: htys755 时间: 2008-12-09 综合评分: 4 积分/C币:3 android socket ...

下载

2018年05月09日 00:00

Android 通过wifi进行p2p通讯和文件传送

android 4.0以上通过wifi进行通讯,不需要服务器,点对点技术,适合局域网聊天,或者...

下载

2018年05月08日 00:00

Visual C++网络通信编程实用案例精选(点对点文件传输、大型文件传输、端口扫描程序、网络五子棋系统等)

2009年05月15日 19.31MB 下载

使用Socket实现点对点文件传输

System.Sockes命名空间了实现 Berkeley 套接字接口。通过这个类,我们可以实现网络计算机之间的消息传输和发送。而在我下面要讨论的这个议题里,我们将讨论的是用套接字实现文件的传输.这种...

zhwfnh zhwfnh

2010-04-18 23:14:00

阅读数:829

java socket实现的点对点文件传输

2009年08月12日 12KB 下载

Qt 实现的简单网络文件传输

2014年06月11日 11KB 下载

MFC Csocket实现点对点文件传输

2009年05月11日 1.92MB 下载

局域网文件传输方式分析

一、概述 在C/S结构的软件开发过程中通常被限于局域网范围内, 常常会遇到需要传输数据文件、音视频文件、升级文件到服务器端或者客户端。每个工作站点都是通过交换机或者集线器、路由器等设备相互连接在一起...

pengchua pengchua

2012-06-14 17:50:51

阅读数:6357

QQ传输文件原理参考(来自互联网)

QQ的文件发送是怎样的过程呢?通常,发送文件的计算机首先要通过消息服务器将其IP地址发送给接收计算机,当接收计算机同意接收的确认消息反馈到消息服务器后,消息服务器将据此设置好文件传输对话。随即,发送计...

educast educast

2013-09-23 15:39:40

阅读数:7912

安卓Android 通过wifi进行p2p通讯和文件传送

2015年06月01日 1MB 下载

个人资料

关注
原创
413
粉丝
214
喜欢
55
评论
41
等级:
访问:
10万+
积分:
4693
排名:
8037
勋章:

最新文章

  • Android DataBinding 从入门到进阶
  • 高手不得不知的List细节
  • Android基于注解IOC组件化/模块化的架构实践
  • 轻松打造一个自己的注解框架
  • 组件化在项目中的使用姿势

归档

  • 2018年5月19篇
  • 2018年4月26篇
  • 2018年3月23篇
  • 2018年2月14篇
  • 2018年1月22篇
  • 2017年12月18篇
  • 2017年11月16篇
  • 2017年10月16篇
  • 2017年9月21篇
  • 2017年8月22篇
  • 2017年7月21篇
  • 2017年6月22篇
  • 2017年5月21篇
  • 2017年4月18篇
  • 2017年3月23篇
  • 2017年2月19篇
  • 2017年1月17篇
  • 2016年12月21篇
  • 2016年11月22篇
  • 2016年10月18篇
  • 2016年9月16篇
  • 2016年8月23篇
  • 2016年7月21篇
  • 2016年6月14篇
  • 2016年5月16篇
  • 2016年4月1篇
  • 2016年3月1篇

展开

热门文章

  • 教你免费且快速地搭建个人网站

    阅读量:8406

  • 国产 Android 权限申请最佳适配方案——permissions4m

    阅读量:3512

  • 自定义View之王者荣耀等级进度条

    阅读量:3261

  • 实现一个类似QQ的社交聊天工具

    阅读量:2310

  • 讲给Android程序员看的前端和后台教程

    阅读量:2300

最新评论

  • 高手不得不知的List细节

    myy629464:归纳总结是知识积累的好方法之一。感谢博主。

  • Java数据结构学习,从源码角度彻...

    myy629464:玉笙弹尽断人肠,只缘一梦枕黄粱。

  • Android 7.0关于HTTP...

    kuailyanghui:你好,按照你说的步骤,在wifi走代理时都是可以抓包的。 但是当把wifi的代理去掉后,这样的ap...

  • Android Realm详解

    jw2268136570:写的很好

  • 教你编写一个手势解锁控件

    weixin_39272004:哇,这就是微信公众号的文章啊,正需要

  • 0


  • 目录

  • 收藏

  • 评论

  • 微信

  • 微博

  • QQ
关闭

你可能感兴趣的:(无网络传输android)