A recent project required the implementation of a function for transferring files between Android phones without a network. I discovered a function called Wifi P2P (Wifi peer-to-peer), and finally implemented the function of transferring files over Wifi. Here I will also organize the code and share it with everyone. Wifi P2P is a feature added in Android 4.0 and higher versions. Through Wifi P2P, you can directly exchange data with paired devices without connecting to the network. Compared with Bluetooth, Wifi P2P has faster search and transmission speeds and a longer transmission distance. The effect achieved is as follows: Generally speaking, the development steps are divided into the following points: - Declare relevant permissions (network and file read and write permissions) in AndroidManifest
- Get WifiP2pManager, register related broadcasts to monitor the status changes of Wifi Direct
- Designate a device as a server (to receive files), create a group and act as a group owner, listen for client connection requests on the designated port, and wait for clients to initiate connection requests and file transfer requests.
- The client (used to send files) actively searches for nearby devices, joins the group created by the server, obtains the server's IP address, and initiates a file transfer request to it
- Verify file integrity
1. Declare permissions Wifi P2P technology does not access the network, but because it uses Java sockets, it needs to apply for network permissions. In addition, because it is to achieve file transfer, it also needs to apply for SD card read and write permissions. - <uses-permission android: name = "android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android: name = "android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android: name = "android.permission.CHANGE_NETWORK_STATE" />
- <uses-permission android: name = "android.permission.INTERNET" />
- <uses-permission android: name = "android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android: name = "android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android: name = "android.permission.READ_EXTERNAL_STORAGE" />
2. Register Broadcast The broadcasts related to Wifi P2P are as follows: - WIFI_P2P_STATE_CHANGED_ACTION (used to indicate whether Wifi P2P is available)
- WIFI_P2P_PEERS_CHANGED_ACTION (The peer list has changed)
- WIFI_P2P_CONNECTION_CHANGED_ACTION (Wifi P2P connection status has changed)
- WIFI_P2P_THIS_DEVICE_CHANGED_ACTION (The device information of this device has changed)
When receiving these broadcasts, we need to go to WifiP2pManager (peer network manager) to make corresponding information requests. In addition, we also need to use the Channel object as a request parameter. - mWifiP2pManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
- mChannel = mWifiP2pManager.initialize(this, getMainLooper(), this);
When receiving the WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION broadcast, you can determine whether the current Wifi P2P is available - int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
- mDirectActionListener.wifiP2pEnabled( true );
- } else {
- mDirectActionListener.wifiP2pEnabled( false );
- }
When the WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION broadcast is received, it means that the list of available devices around the device has changed. You can get the list of available devices through the requestPeers method, and then you can select one of the devices to connect to. - mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() { @Override
- public void onPeersAvailable(WifiP2pDeviceList peers) {
- mDirectActionListener.onPeersAvailable(peers.getDeviceList());
- }
- });
When WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION broadcast is received, it means that the connection status of Wifi P2P has changed, which may be connected to a device or disconnected from a device. - 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, "Connected to p2p device" );
- } else {
- mDirectActionListener.onDisconnection();
- Log.e(TAG, "Disconnected from p2p device" );
- }
If it is connected to a device, you can get the connection information through the requestConnectionInfo method When receiving the WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION broadcast, you can get the device information after the device changes. - (WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE)
It can be seen that the Wifi P2P interface is highly asynchronous. So far, three system callback functions have been used, one for initializing WifiP2pManager and two for asynchronously requesting data in broadcasting. In order to simplify the operation, a custom callback function is used here, and the method meaning is consistent with the system callback function. - public interface DirectActionListener extends WifiP2pManager.ChannelListener {
- void wifiP2pEnabled(boolean enabled);
- void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo);
- void onDisconnection();
- void onSelfDeviceAvailable(WifiP2pDevice wifiP2pDevice);
- void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList);
- }
So, all the code used by the entire broadcast receiver is: - /**
-
- * Author: chenZY
-
- * Time: 2018/2/9 17:53
-
- * describe:
-
- */
- 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, "Received broadcast: " + intent.getAction());
- if (!TextUtils.isEmpty(intent.getAction())) {
- switch (intent.getAction()) {
- // Used to indicate whether Wifi P2P is available
- 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<WifiP2pDevice> wifiP2pDeviceList = new ArrayList<>();
- mDirectActionListener.onPeersAvailable(wifiP2pDeviceList);
- }
- break;
- }
-
- // The peer list has changed
- case WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION: {
- mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
- @Override
- public void onPeersAvailable(WifiP2pDeviceList peers) {
- mDirectActionListener.onPeersAvailable(peers.getDeviceList());
- }
- });
- break;
- }
- // The Wifi P2P connection status has changed
- 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, "Connected to p2p device" );
- } else {
- mDirectActionListener.onDisconnection();
- Log.e(TAG, "Disconnected from p2p device" );
- }
- break;
- }
-
- //The device information of this device has changed
- case WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION: {
- mDirectActionListener.onSelfDeviceAvailable((WifiP2pDevice) intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
- break;
- }
- }
- }
- }
- }
3. Create a group on the server Assume that when device A searches for device B and connects to device B, the system will automatically create a group and randomly designate a device as the group owner. At this point, the IP address of the group owner is known to both devices (provided in the system callback function), but the client's IP address needs to be actively obtained through other methods. For example, after the device is successfully connected, the client can actively initiate a Socket connection request to the server, and the server listens for the client's connection request on the specified port. When the connection is successful, the server can obtain the client's IP address. To simplify the operation, we will directly specify a device as the server (group owner), that is, directly specify a device to receive files. Therefore, the server needs to actively create a group and wait for the client to connect. - 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" );
- }
- });
Here, IntentService is used to listen to the client's Socket connection request in the background and transfer files through input and output streams. The code here is relatively simple. It just blocks the specified port to listen to the client's connection request, obtains the file information model FileTransfer to be transferred, and then performs the actual data transfer. - @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, "Client IP address: " + client.getInetAddress().getHostAddress());
- inputStream = client.getInputStream();
- objectInputStream = new ObjectInputStream(inputStream);
- FileTransfer fileTransfer = (FileTransfer) objectInputStream.readObject();
- Log.e(TAG, "File to be received: " + fileTransfer);
- String name = new File(fileTransfer.getFilePath()).getName();
-
- //Store the file in the specified location
- 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, "File receiving progress: " + 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, "File received successfully, the MD5 code of the file is: " + Md5Util.getMd5(file));
- } catch (Exception e) {
- Log.e(TAG, "File receiving Exception: " + e.getMessage());
- finally
- clean();
- if (progressChangListener != null ) {
- progressChangListener.onTransferFinished(file);
- }
- //Start the service again and wait for the next client connection
- startService(new Intent(this, WifiServerService.class));
- }
- }
Because the client may initiate connection requests multiple times, when the file transfer is completed here (regardless of success or failure), you need to restart the Service to make the service block again and wait for the client's connection request. FileTransfer contains three fields. The MD5 code value is used to verify the integrity of the file, and fileLength is used to calculate the transfer progress of the file. - public class FileTransfer implements Serializable {
- //File path
- private String filePath;
- //File size
- private long fileLength;
- //MD5 code
- private String md5;
- ···
- }
In order to publish the file transfer progress to the external interface, in addition to starting the Service, the interface also needs to bind the Service. Here, an interface for updating the file transfer status is needed. - public interface OnProgressChangListener {
- //When the transfer progress changes
- void onProgressChanged(FileTransfer fileTransfer, int progress);
- //When the transfer is finished
- void onTransferFinished(File file);
- }
Therefore, you need to pass progressChangListener as a parameter to WifiServerService and update the progress dialog when the progress changes. - 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( "File name: " + 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());
- }
- }
- });
- }
- };
4. The client joins the group and initiates a file transfer request The file sending interface SendFileActivity needs to implement the DirectActionListener interface First, you need to register P2P broadcast to obtain surrounding device information and connection status. - @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());
- }
Use the discoverPeers method to search for peripheral devices. The callback function is used to notify whether the method is successfully called. - mWifiP2pManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() { @Override
- public void onSuccess() {
- showToast( "Success" );
- }
-
- @Override
- public void onFailure( int reasonCode) {
- showToast( "Failure" );
- loadingDialog.cancel();
- }
- });
When the search is finished, the system will trigger the WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION broadcast. At this time, you can call the requestPeers method to obtain the device list information. Here, RecyclerView is used to display the list, and the list is refreshed in the onPeersAvailable method. - mWifiP2pManager.requestPeers(mChannel, new WifiP2pManager.PeerListListener() {
- @Override
- public void onPeersAvailable(WifiP2pDeviceList peers) {
- mDirectActionListener.onPeersAvailable(peers.getDeviceList());
- }
- });
-
- @Override
- public void onPeersAvailable(Collection<WifiP2pDevice> wifiP2pDeviceList) {
- Log.e(TAG, "onPeersAvailable :" + wifiP2pDeviceList. size ());
- this.wifiP2pDeviceList.clear();
- this.wifiP2pDeviceList.addAll(wifiP2pDeviceList);
- deviceAdapter.notifyDataSetChanged();
- loadingDialog.cancel();
- }
After that, select the group owner (server) device through the click event and request to connect to it through the connect method - private void connect () {
- WifiP2pConfig config = new WifiP2pConfig();
- if (config.deviceAddress != null && mWifiP2pDevice != null ) {
- config.deviceAddress = mWifiP2pDevice.deviceAddress;
- config.wps.setup = WpsInfo.PBC;
- showLoadingDialog( "Connecting " + 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( "Connection failed " + reason);
- dismissLoadingDialog();
- }
- });
- }
- }
Here, the connection result cannot be determined by the function function. You need to rely on the WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION method issued by the system to obtain the connection result. Here, you can obtain the group connection information through requestConnectionInfo. The information is finally passed through the onConnectionInfoAvailable method. Here you can determine whether the current device is the group owner and obtain the group IP address. - @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( "Connected device name: " );
- stringBuilder.append(mWifiP2pDevice.deviceName);
- stringBuilder.append( "\n" );
- stringBuilder.append( "Address of the connected device:" );
- stringBuilder.append(mWifiP2pDevice.deviceAddress);
- }
-
- stringBuilder.append( "\n" );
- stringBuilder.append( "Is this the group owner: " );
- stringBuilder.append(wifiP2pInfo.isGroupOwner ? "Is group owner" : "Not group owner" );
- stringBuilder.append( "\n" );
- stringBuilder.append( "Group owner's IP address: " );
- stringBuilder.append(wifiP2pInfo.groupOwnerAddress.getHostAddress());
- tv_status.setText(stringBuilder);
- if (wifiP2pInfo.groupFormed && !wifiP2pInfo.isGroupOwner) {
- this.wifiP2pInfo = wifiP2pInfo;
- }
- }
At this point, the server and client have been connected through Wifi P2P, and the client has obtained the IP address of the server. After selecting the file to be sent, it can actively initiate a connection request to the server. Method to initiate file selection - Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
- intent.setType( "*/*" );
- intent.addCategory(Intent.CATEGORY_OPENABLE);
- startActivityForResult(intent, 1);
Get the actual path of the selected file - @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, "File to be sent: " + 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 ;
- }
The file sending operation is processed in AsyncTask, and the server IP address is passed in as a parameter. Before the file is officially sent, the information model FileTransfer containing the file information (file name, file size, file MD5 code) is sent first, and the progress is updated during the file sending process. - /**
- * Author: Ye Ying Shi Ye
- * Time: 2018/2/15 8:51
- * Description: The client sends a file
- */
-
- 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( "Sending file" );
- 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, "The MD5 code value of the file is: " + 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, "File sending progress: " + progress);
- }
- outputStream. close ();
- objectOutputStream. close ();
- inputStream.close ();
- socket.close () ;
- outputStream = null ;
- objectOutputStream = null ;
- inputStream = null ;
- socket = null ;
- Log.e(TAG, "File sent successfully" );
-
- return true ;
-
- } catch (Exception e) {
- Log.e(TAG, "File sending exception 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);
- }
- }
5. Verify file integrity The integrity of the transferred file is mainly ensured by calculating the MD5 code value of the file. Before sending the file, the calculation is performed in the doInBackground method of WifiClientTask, and the MD5 code value is assigned to the FileTransfer model. It is calculated by the following method - /**
- * Author: Ye Ying Shi Ye
- * Time: 2018/2/14 21:16
- * describe:
- */
- 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();
- }
- }
Because the client will send FileTransfer to the server, the server can recalculate the MD5 code value of the file after the file transfer is completed and compare it to determine whether the file is complete. Code address: https://github.com/leavesC/WifiP2P |