使用wifi直连在安卓设备之间传输数据?

3

我最近将WiFi直连功能引入我的项目中,我的目标是在满足我的应用程序条件时,在两个WiFi直连连接设备之间传递字符串值。现在我已列出所有对等点,并且还建立了所选对等点之间的连接。我的想法是在设备之间传递一个JSON文件。因此,在尝试执行该想法之前,我尝试在两个设备之间传递图像文件。我按照Android WiFi直连教程中的步骤进行操作。列出对等点并连接对等点都成功了,但我无法在设备之间传递数据。以下是我的代码。 FileTransferService.java

package jing.app.directwifi;

import android.app.IntentService;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
 import android.util.Log;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetSocketAddress;
import java.net.Socket;


/**
 * A service that process each file transfer request i.e Intent by opening a
 * socket connection with the WiFi Direct Group Owner and writing the file
 */
public class FileTransferService extends IntentService {

private static final int SOCKET_TIMEOUT = 5000;
public static final String ACTION_SEND_FILE = "jing.app.directwifi.SEND_FILE";
public static final String EXTRAS_FILE_PATH = "file_url";
public static final String EXTRAS_GROUP_OWNER_ADDRESS = "go_host";
public static final String EXTRAS_GROUP_OWNER_PORT = "go_port";

public FileTransferService(String name) {
    super(name);
}

public FileTransferService() {
    super("FileTransferService");
}

/*
 * (non-Javadoc)
 * @see android.app.IntentService#onHandleIntent(android.content.Intent)
 */
@Override
protected void onHandleIntent(Intent intent) {

    Context context = getApplicationContext();
    if (intent.getAction().equals(ACTION_SEND_FILE)) {
        String fileUri = intent.getExtras().getString(EXTRAS_FILE_PATH);
        String host = intent.getExtras().getString(EXTRAS_GROUP_OWNER_ADDRESS);
        Socket socket = new Socket();
        int port = intent.getExtras().getInt(EXTRAS_GROUP_OWNER_PORT);

        try {
           // Log.d(WiFiDirectActivity.TAG, "Opening client socket - ");
            socket.bind(null);
            socket.connect((new InetSocketAddress(host, port)), SOCKET_TIMEOUT);

            Log.d("connected", "Client socket - " + socket.isConnected());
            OutputStream stream = socket.getOutputStream();
            ContentResolver cr = context.getContentResolver();
            InputStream is = null;
            try {
                is = cr.openInputStream(Uri.parse(fileUri));
            } catch (FileNotFoundException e) {
                Log.d("exp", e.toString());
            }
           MainActivity.copyFile(is, stream);
            Log.d("exp" ,"Client: Data written");
        } catch (IOException e) {
            Log.e("exp", e.getMessage());
        } finally {
            if (socket != null) {
                if (socket.isConnected()) {
                    try {
                        socket.close();
                    } catch (IOException e) {
                        // Give up
                        e.printStackTrace();
                    }
                }
            }
        }

    }
}
}

主活动.java

package jing.app.directwifi;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;





import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.net.wifi.p2p.WifiP2pConfig;
import android.net.wifi.p2p.WifiP2pDevice;
 import android.net.wifi.p2p.WifiP2pDeviceList;
import android.net.wifi.p2p.WifiP2pInfo;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.ActionListener;
import android.net.wifi.p2p.WifiP2pManager.Channel;
import android.net.wifi.p2p.WifiP2pManager.ConnectionInfoListener;
import android.net.wifi.p2p.WifiP2pManager.PeerListListener;
import android.os.AsyncTask;
import android.os.Bundle;
 import android.os.Environment;
import android.provider.Settings;
import android.util.Log;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener,   android.content.DialogInterface.OnClickListener, ConnectionInfoListener {

private WifiP2pManager mManager;
private Channel mChannel;
private BroadcastReceiver mReceiver;
private IntentFilter mIntentFilter;

private Button mDiscover;
private TextView mDevices;
public ArrayAdapter mAdapter;
private ArrayList<WifiP2pDevice> mDeviceList = new ArrayList<WifiP2pDevice>();
protected static final int CHOOSE_FILE_RESULT_CODE = 20;
int flag=0;
@Override
protected void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mDiscover = (Button) findViewById(R.id.discover);
    mDiscover.setOnClickListener(this);

    mDevices = (TextView) findViewById(R.id.peers);

    mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mManager.initialize(this, getMainLooper(), null);
    mReceiver = new WiFiDirectReceiver(mManager, mChannel, this);

    mIntentFilter = new IntentFilter();
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION);
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION);
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
    mIntentFilter.addAction(WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION);


}

@Override
protected void onResume() {
    super.onResume();
    registerReceiver(mReceiver, mIntentFilter);
}

@Override
protected void onPause() {
    super.onPause();
    unregisterReceiver(mReceiver);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    getMenuInflater().inflate(R.menu.activity_main, menu);
    return true;
}

private class WiFiDirectReceiver extends BroadcastReceiver {

    private WifiP2pManager mManager;
    private Channel mChannel;
    private MainActivity mActivity;

    public WiFiDirectReceiver(WifiP2pManager manager, Channel channel, MainActivity activity) {
        super();
        mManager = manager;
        mChannel = channel;
        mActivity = activity;
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {

            int state = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
            if (state == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
                   String title = "ANDROID_ID[" + getAndroid_ID() + "]";
                   title += "   MAC[" + getMACAddress() + "]";
                Toast.makeText(mActivity, "Wi-Fi Direct is enabled."+title, Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(mActivity, "Wi-Fi Direct is disabled.", Toast.LENGTH_SHORT).show();
            }

        } else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)) {

            if (mManager != null) {
                mManager.requestPeers(mChannel, new PeerListListener() {

                    @Override
                    public void onPeersAvailable(WifiP2pDeviceList peers) {
                        if (peers != null) {
                            mDeviceList.addAll(peers.getDeviceList());
                            ArrayList<String> deviceNames = new ArrayList<String>();
                            for (WifiP2pDevice device : mDeviceList) {
                                deviceNames.add(device.deviceName);
                            }
                            if (deviceNames.size() > 0) {
                                mAdapter = new ArrayAdapter<String>(mActivity, android.R.layout.simple_list_item_1, deviceNames);
                                if(flag==0)
                                {
                                    flag=1;
                                showDeviceListDialog();
                                }
                            } else {
                                Toast.makeText(mActivity, "Device list is empty.", Toast.LENGTH_SHORT).show();
                            }
                        }
                    }
                });
            }

        } else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {


        } else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {

        }
    }

}

@Override
public void onClick(View v) {
    switch (v.getId()) {
    case R.id.discover:
        onDiscover();
        break;
    }
}

private void onDiscover() {
    mManager.discoverPeers(mChannel, new ActionListener() {

        @Override
        public void onSuccess() {
            Toast.makeText(MainActivity.this, "Discover peers successfully.", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(int reason) {
            Toast.makeText(MainActivity.this, "Discover peers failed.", Toast.LENGTH_SHORT).show();
        }
    });
}

private void showDeviceListDialog() {
    DeviceListDialog deviceListDialog = new DeviceListDialog();
    deviceListDialog.show(getFragmentManager(), "devices");
}

private class DeviceListDialog extends DialogFragment {

    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Select a device")
               .setSingleChoiceItems(mAdapter, 0, MainActivity.this)
               .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {

                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        dialog.dismiss();
                    }

               });

        return builder.create();
    }

}

@Override
public void onClick(DialogInterface dialog, int which) {
    onDeviceSelected(which);
    dialog.dismiss();
}

private void onDeviceSelected(int which) {
    WifiP2pDevice device = mDeviceList.get(which);
    if (device == null) {
        return;
    }

    WifiP2pConfig config = new WifiP2pConfig();
    config.deviceAddress = device.deviceAddress;
    mManager.connect(mChannel, config, new ActionListener() {

        @Override
        public void onSuccess() {
            Toast.makeText(MainActivity.this, "Connected", Toast.LENGTH_SHORT).show();
              Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
              intent.setType("image/*");
              startActivityForResult(intent, CHOOSE_FILE_RESULT_CODE);
        }

        @Override
        public void onFailure(int reason) {
            Toast.makeText(MainActivity.this, "Failed to connect", Toast.LENGTH_SHORT).show();
        }
    });
}
/**
 * ANDROID_ID
 */
private String getAndroid_ID() {
    return Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID);
}

/**
 * Wi-Fi MAC
 */
private String getMACAddress() {
    WifiManager manager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
    WifiInfo wifiInfo = manager.getConnectionInfo();
    String mac = wifiInfo.getMacAddress();

    // After the group negotiation, we assign the group owner as the file
    // server. The file server is single threaded, single connection server
    // socket.

        new FileServerAsyncTask(getApplicationContext())
                .execute();





    return mac;
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {

    // User has picked an image. Transfer it to group owner i.e peer using
    // FileTransferService.
    Uri uri = data.getData();

  Log.d("intent", "Intent----------- " + uri);
    Intent serviceIntent = new Intent(MainActivity.this, FileTransferService.class);
    serviceIntent.setAction(FileTransferService.ACTION_SEND_FILE);
    serviceIntent.putExtra(FileTransferService.EXTRAS_FILE_PATH, uri.toString());
    serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_ADDRESS,
            getMACAddress());
    serviceIntent.putExtra(FileTransferService.EXTRAS_GROUP_OWNER_PORT, 8988);
    startService(serviceIntent);
}
/**
 * A simple server socket that accepts connection and writes some data on
 * the stream.
 */
public static class FileServerAsyncTask extends AsyncTask<Void, Void, String> {

    private Context context;


    /**
     * @param context
     * @param statusText
     */
    public FileServerAsyncTask(Context context) {
        this.context = context;

    }

    @Override
    protected String doInBackground(Void... params) {
        try {
            System.out.println("insideeeeeeeeeeeeeeeeeeeeeeee");
            ServerSocket serverSocket = new ServerSocket(8988);
            Log.d("Server: Socket opened", "Server: Socket opened");
            Socket client = serverSocket.accept();
            Log.d("Server: connection done", "Server: connection done");
            final File f = new File(Environment.getExternalStorageDirectory() + "/"
                    + context.getPackageName() + "/wifip2pshared-" +   System.currentTimeMillis()
                    + ".jpg");

            File dirs = new File(f.getParent());
            if (!dirs.exists())
                dirs.mkdirs();
            f.createNewFile();

            Log.d("server: copying files ", "server: copying files " + f.toString());
            InputStream inputstream = client.getInputStream();
            copyFile(inputstream, new FileOutputStream(f));
            serverSocket.close();
            return f.getAbsolutePath();
        } catch (IOException e) {
            Log.e("exp", e.getMessage());
            System.out.println(":iooo:"+e);
            return null;
        }
    }

    /*
     * (non-Javadoc)
     * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
     */
    @Override
    protected void onPostExecute(String result) {
        if (result != null) {

            Intent intent = new Intent();
            intent.setAction(android.content.Intent.ACTION_VIEW);
            intent.setDataAndType(Uri.parse("file://" + result), "image/*");
            context.startActivity(intent);
        }

    }

    /*
     * (non-Javadoc)
     * @see android.os.AsyncTask#onPreExecute()
     */
    @Override
    protected void onPreExecute() {

    }

}
public static boolean copyFile(InputStream inputStream, OutputStream out) {
    byte buf[] = new byte[1024];
    int len;
    long startTime=System.currentTimeMillis();

    try {
        while ((len = inputStream.read(buf)) != -1) {
            out.write(buf, 0, len);
        }
        out.close();
        inputStream.close();
        long endTime=System.currentTimeMillis()-startTime;
        Log.v("","Time taken to transfer all bytes is : "+endTime);

    } catch (IOException e) {
        Log.d("exp", e.toString());
        return false;
    }
    return true;
}

@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
    // TODO Auto-generated method stub

    Toast.makeText(getApplicationContext(), "connectioninfoo", 3000).show();

}

}

清单文件
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="jing.app.directwifi"
android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="14"
    android:targetSdkVersion="16" />

<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.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- Market filtering -->
<uses-feature
    android:name="android.hardware.wifi.direct"
    android:required="true" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="jing.app.directwifi.MainActivity"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    <!-- Used for transferring files  after a successful connection -->
    <service
        android:name=".FileTransferService"
        android:enabled="true" />
</application>

</manifest>

这些是我代码中使用的文件。从教程中我发现以下内容:

new FileServerAsyncTask(getApplicationContext()) .execute();

这里接受传入的数据,所以当我需要执行这个异步线程时,我在哪个部分犯了错误呢?如何在设备之间传输文件?

如果您在 Wi-Fi 直连示例上使用完全相同的代码,则整个程序的任何过程都不会出现问题。尽管如此,我建议您特别针对 copyFile 方法调试您的代码。 - misterbaykal
2个回答

9

这个演示wifi直连项目的安卓代码只支持单向传输文件。也就是说,你只能从客户端发送文件到服务器端。要实现双向传输,需要进一步修改。

编辑2:

为了实现双向传输,你需要知道连接的两个对等设备的IP地址。使用下面的函数,我在各种来源的基础上进行了适当的修改。

    public static String getIpAddress() {
    try {
        List<NetworkInterface> interfaces = Collections
                .list(NetworkInterface.getNetworkInterfaces());
        /*
         * for (NetworkInterface networkInterface : interfaces) { Log.v(TAG,
         * "interface name " + networkInterface.getName() + "mac = " +
         * getMACAddress(networkInterface.getName())); }
         */

        for (NetworkInterface intf : interfaces) {
            if (!getMACAddress(intf.getName()).equalsIgnoreCase(
                    Globals.thisDeviceAddress)) {
                // Log.v(TAG, "ignore the interface " + intf.getName());
                // continue;
            }
            if (!intf.getName().contains("p2p"))
                continue;

            Log.v(TAG,
                    intf.getName() + "   " + getMACAddress(intf.getName()));

            List<InetAddress> addrs = Collections.list(intf
                    .getInetAddresses());

            for (InetAddress addr : addrs) {
                // Log.v(TAG, "inside");

                if (!addr.isLoopbackAddress()) {
                    // Log.v(TAG, "isnt loopback");
                    String sAddr = addr.getHostAddress().toUpperCase();
                    Log.v(TAG, "ip=" + sAddr);

                    boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr);

                    if (isIPv4) {
                        if (sAddr.contains("192.168.49.")) {
                            Log.v(TAG, "ip = " + sAddr);
                            return sAddr;
                        }
                    }

                }

            }
        }

    } catch (Exception ex) {
        Log.v(TAG, "error in parsing");
    } // for now eat exceptions
    Log.v(TAG, "returning empty ip address");
    return "";
}

public static String getMACAddress(String interfaceName) {
        try {
            List<NetworkInterface> interfaces = Collections
                    .list(NetworkInterface.getNetworkInterfaces());

            for (NetworkInterface intf : interfaces) {
                if (interfaceName != null) {
                    if (!intf.getName().equalsIgnoreCase(interfaceName))
                        continue;
                }
                byte[] mac = intf.getHardwareAddress();
                if (mac == null)
                    return "";
                StringBuilder buf = new StringBuilder();
                for (int idx = 0; idx < mac.length; idx++)
                    buf.append(String.format("%02X:", mac[idx]));
                if (buf.length() > 0)
                    buf.deleteCharAt(buf.length() - 1);
                return buf.toString();
            }
        } catch (Exception ex) {
        } // for now eat exceptions
        return "";
        /*
         * try { // this is so Linux hack return
         * loadFileAsString("/sys/class/net/" +interfaceName +
         * "/address").toUpperCase().trim(); } catch (IOException ex) { return
         * null; }
         */
    }

我无法在两个方向上发送图像。实际上,我无法获取客户端的IP地址,即非组所有者对等体。 - Abhishek choudhary
有一个名为 getMACAddress 的方法在哪里..?? - Umang Kothari
Globals.thisDeviceAddress是什么?我收到了一个错误消息,提示无法解析变量Globals。 为什么要使用Globals?为什么不使用device.deviceAddress? - ahmedibrahim085
目前的函数没有设备作为参数,因此我已经使用了那个。 - Dipendra

1
我认为您初始化客户端的方式有问题。您需要调用以下代码:

new FileServerAsyncTask(getApplicationContext()).execute();

在建立连接后,检查是否为客户端。

现在只有在它是服务器(组所有者)并且每次调用获取MAC地址时才创建客户端套接字。

因此,在客户端上,您没有初始化套接字,因此无法接收文件。

请检查SDK中提供的WifiDirect示例演示,您可能会获得更多想法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接