使用 Wi-Fi 创建 P2P 连接:消息传递问题

Posted

技术标签:

【中文标题】使用 Wi-Fi 创建 P2P 连接:消息传递问题【英文标题】:Creating P2P Connections with Wi-Fi : Message passing issue 【发布时间】:2017-04-14 07:07:15 【问题描述】:

我正在使用 Wifi P2P 连接使用以下教程在两个 android 设备之间发送和接收消息

https://developer.android.com/training/connect-devices-wirelessly/wifi-direct.html

https://developer.android.com/guide/topics/connectivity/wifip2p.html

它正在识别附近的设备并与附近的对等点连接。但是在我的代码中,在服务器和客户端之间连接成功后,客户端对等点在服务器对等点无法向客户端对等点发送消息后成功向服务器对等点发送消息,并且它给出了以下例外

04-14 12:31:27.740: E/test(6037): SERVER to CLIENT message sending exception: bind failed: EADDRINUSE (Address already in use)

请帮忙看看我的代码有什么问题

这是我的 MainActivity.java

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnClickListener, PeerListListener, ConnectionInfoListener

WifiP2pManager mManager;
Channel mChannel;
private List<WifiP2pDevice> peers = new ArrayList<WifiP2pDevice>();
BroadcastReceiver mReceiver;
IntentFilter mIntentFilter;
private BroadcastReceiver receiver = null;
private WifiP2pInfo info;
String groupOwnerAddress;

ListView listPeers;
TextView mTextDeviceName, mTextStatus, mTextGroupOwner;
EditText mEditText_message;
Context context;
static String toastmessage;
static String message = "";
boolean isPeerServer;

@Override
protected void onCreate(Bundle savedInstanceState) 
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    context = MainActivity.this;
    getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

    mManager = (WifiP2pManager) getSystemService(Context.WIFI_P2P_SERVICE);
    mChannel = mManager.initialize(this, getMainLooper(), null);
    mReceiver = new WifiP2PBroadCast(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);

    findViewById(R.id.button_search).setOnClickListener(this);
    findViewById(R.id.button_send).setOnClickListener(this);

    listPeers = (ListView) findViewById(R.id.list_peers);
    mTextDeviceName = (TextView) findViewById(R.id.text_device_name);
    mTextStatus = (TextView) findViewById(R.id.text_Status);
    mTextGroupOwner = (TextView) findViewById(R.id.text_group_owner);
    mEditText_message = (EditText) findViewById(R.id.edittext_message);

    listPeers.setOnItemClickListener(new OnItemClickListener() 

        @Override
        public void onItemClick(AdapterView<?> arg0, View arg1, int position, long arg3) 
            // TODO Auto-generated method stub
            connectWithPeers(position);
        
    );


@Override
protected void onResume() 
    // TODO Auto-generated method stub
    super.onResume();
    receiver = new WifiP2PBroadCast(mManager, mChannel, this);
    registerReceiver(mReceiver, mIntentFilter);
    discoverPeers();


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


public void updateDeviceInfo(WifiP2pDevice device) 
    mTextDeviceName.setText(device.deviceName);
    mTextStatus.setText(getDeviceStatus(device.status));


private static String getDeviceStatus(int deviceStatus) 
    switch (deviceStatus) 
        case WifiP2pDevice.AVAILABLE:
            return "Available";
        case WifiP2pDevice.INVITED:
            return "Invited";
        case WifiP2pDevice.CONNECTED:
            return "Connected";
        case WifiP2pDevice.FAILED:
            return "Failed";
        case WifiP2pDevice.UNAVAILABLE:
            return "Unavailable";
        default:
            return "Unknown";
    


@Override
public void onClick(View v) 
    // TODO Auto-generated method stub
    switch (v.getId()) 
        case R.id.button_search:
            discoverPeers();
            break;
        case R.id.button_send:
            sendMessage();
            break;
        default:
            break;
    



public void discoverPeers()
    mManager.discoverPeers(mChannel, new WifiP2pManager.ActionListener() 
        @Override
        public void onSuccess() 
            Log.e("test", "Discovering Peers Success..");
            if (mManager != null) 
                mManager.requestPeers(mChannel, MainActivity.this);
            
        

        @Override
        public void onFailure(int reasonCode) 
           Log.e("test", "Discovering Peers Fail..");
        
    );


public void connectWithPeers(int id) 
    WifiP2pDevice device = peers.get(id);
    WifiP2pConfig config = new WifiP2pConfig();
    config.deviceAddress = device.deviceAddress;
    mManager.connect(mChannel, config, new ActionListener() 

        @Override
        public void onSuccess() 
            //success logic
            Log.e("test", "Connection with peer Success..");
        

        @Override
        public void onFailure(int reason) 
            //failure logic
            Log.e("test", "Connection with peer Failed..");
        
    );


public void sendMessage() 
    if (!isPeerServer) 
        //Client Peer
        Toast.makeText(MainActivity.this, "client sending message", Toast.LENGTH_SHORT).show();
        new SendMessage().execute(MainActivity.this);
     else 
        //Server Peer
        Toast.makeText(MainActivity.this, "server sending message", Toast.LENGTH_SHORT).show();
        new FileServerAsyncTask(this, "").execute();
    



//Send message form client to server
public class SendMessage extends AsyncTask 
    @Override
    protected Object doInBackground(Object... arg0) 
        // TODO Auto-generated method stub
        try 
            message = mEditText_message.getText().toString();

            Socket socket = new Socket(info.groupOwnerAddress.getHostAddress(), 8988);
            //Send the message to the server
            OutputStream os = socket.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(os);
            BufferedWriter bw = new BufferedWriter(osw);

            String number = message;

            String sendMessage = number + "\n";
            bw.write(sendMessage);
            bw.flush();
            Log.e("test", "Message sent to the server : "+sendMessage);

            //Get the return message from the server
            InputStream is = socket.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            String message = br.readLine();
            Log.e("test", "Message received from the server : " +message);
            socket.close();
        catch(IOException e)
            Log.e("test", "CLIENT to SERVER message sending exception: "+e.getMessage());
        finally 
        
        return null;
    

    @Override
    protected void onPostExecute(Object result) 
        // TODO Auto-generated method stub
        super.onPostExecute(result);
        Toast.makeText(MainActivity.this, "MESSAGE: "+message, Toast.LENGTH_SHORT).show();
    



@Override
public void onConnectionInfoAvailable(WifiP2pInfo wifiP2pInfo) 
    // TODO Auto-generated method stub
    Log.e("test", "..onConnectionInfoAvailable..");
    info = wifiP2pInfo;
    try 
        groupOwnerAddress = wifiP2pInfo.groupOwnerAddress.getHostAddress();
     catch (Exception e) 
        // TODO: handle exception
        Log.e("test", "Owner Info null");
    

    if (info.groupFormed && info.isGroupOwner) 
        Log.e("test", "GOT INFORMATION FROM PEERS..");
        new FileServerAsyncTask(this, "").execute();
    
    if (wifiP2pInfo.isGroupOwner) 
        isPeerServer = true;
     else 
        isPeerServer = false;
    
    mTextGroupOwner.setText("Is group owner? ---- "+((wifiP2pInfo.isGroupOwner == true) ? "yes" : "no"));


@Override
public void onPeersAvailable(WifiP2pDeviceList peerList) 
    // TODO Auto-generated method stub
    Log.e("test", "NUMBER OF PEERS AVAILABLE: ----- "+peerList.getDeviceList().size());
    peers.clear();
    peers.addAll(peerList.getDeviceList());

    String[] devices = new String[peerList.getDeviceList().size()];
     for (int i = 0; i < devices.length; i++) 
        devices[i] = peers.get(i).deviceName.toString();
     

     try 
         ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, R.layout.simplerow, devices);
         listPeers.setAdapter(adapter); 
     catch (Exception e) 
        // TODO: handle exception
        Log.e("test", "EXCEPTION: "+e.toString());
     



//Send message form server to client
public class FileServerAsyncTask extends AsyncTask<Object, Object, Object> 
    private Context context;
    String message;
    public FileServerAsyncTask(Context context, String statusText) 
        this.context = context;
    
    @Override
    protected Object doInBackground(Object... arg0) 
        // TODO Auto-generated method stub
        Socket socket = null;
        try 

            ServerSocket serverSocket = new ServerSocket(8988);
                //Reading the message from the client
                socket = serverSocket.accept();
                InputStream is = socket.getInputStream();
                InputStreamReader isr = new InputStreamReader(is);
                BufferedReader br = new BufferedReader(isr);
                String number = br.readLine();
                toastmessage = number;
                Log.e("test", "Message received from client is "+number);

                //Multiplying the number by 2 and forming the return message
                String returnMessage;
                returnMessage = "Return message from Server..";//String.valueOf(returnValue) + "\n";

                //Sending the response back to the client.
                OutputStream os = socket.getOutputStream();
                OutputStreamWriter osw = new OutputStreamWriter(os);
                BufferedWriter bw = new BufferedWriter(osw);
                bw.write(returnMessage);
                Log.e("test", "Message sent to the client is "+returnMessage);
                bw.flush();

        catch (Exception e)
            Log.e("test", "SERVER to CLIENT message sending exception: "+e.getMessage());
        finally 
            try
                socket.close();
            
            catch(Exception e)
        
        return null;
    

    @Override
    protected void onPostExecute(Object result) 
        // TODO Auto-generated method stub
        Toast.makeText(MainActivity.this, "Message from Client: "+toastmessage, Toast.LENGTH_SHORT).show();
    




这是我的 WifiP2PBroadCast.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.p2p.WifiP2pDevice;
import android.net.wifi.p2p.WifiP2pManager;
import android.net.wifi.p2p.WifiP2pManager.Channel;

public class WifiP2PBroadCast extends BroadcastReceiver
private WifiP2pManager mManager;
private Channel mChannel;
private MainActivity activity;

public WifiP2PBroadCast(WifiP2pManager manager, Channel channel, MainActivity activity) 
    // TODO Auto-generated constructor stub
    super();
    this.mManager = manager;
    this.mChannel = channel;
    this.activity = activity;

@Override
public void onReceive(Context context, Intent intent) 
    // TODO Auto-generated method stub
    String action = intent.getAction();
    if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) 
        // Respond to new connection or disconnections
        mManager.requestConnectionInfo(mChannel, activity);

     else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) 
        // Respond to this device's wifi state changing
        activity.updateDeviceInfo((WifiP2pDevice) intent.getParcelableExtra(
                WifiP2pManager.EXTRA_WIFI_P2P_DEVICE));
    



这里是 AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.suresh.wifi_p2p_demo"
android:versionCode="1"
android:versionName="1.0" >

<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-sdk
    android:minSdkVersion="15"
    android:targetSdkVersion="25" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name=".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>
</application>

【问题讨论】:

【参考方案1】:

如果您在收到消息时遇到此错误 您需要删除正在使用的组才能继续

    mManager.removeGroup(mChannel, null);

【讨论】:

以上是关于使用 Wi-Fi 创建 P2P 连接:消息传递问题的主要内容,如果未能解决你的问题,请参考以下文章

Wi-Fi P2P 是不是适合本地聊天发现应用程序(类似 Tinder)?

Android Wi-Fi Direct P2P 连接多个设备

Android Wi-Fi Peer-to-Peer(Android的Wi-Fi P2P对等网络)

Wi-Fi与蓝牙对等连接

Wi-Fi p2p & ap 共存

Android Wi-Fi Direct P2P 将数据从服务器发送到客户端