[英]Can't connect to Android devices when using Network Service Discovery through Wi-Fi P2P
大家! 我正在開發一款Android應用,可以與已安裝此應用的附近設備聊天。 為了實現這一目標,我正在使用Wi-Fi P2P API和網絡服務發現來搜索附近的設備。 我編寫了用於在服務啟動的線程中搜索附近設備的代碼。 當檢測到設備時,服務將其(通過廣播意圖)發送到活動,該活動顯示到目前為止檢測到的設備。 檢測到的設備被添加到recyclerView中,當用戶按下其中一個設備時,必須建立與此類設備的連接。 Wi-Fi Direct連接成功建立(即WifiP2pManager.connect()方法成功)並捕獲WIFI_P2P_CONNECTION_CHANGED_ACTION。 在廣播接收器中,當捕獲這樣的廣播意圖時,執行以下代碼:
NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO);
if (networkInfo.isConnected()) {
mManager.requestConnectionInfo(mChannel, connectionInfoListener); }
使用requestConnectionInfo()方法,我可以獲得有關連接的更多信息,例如我正在嘗試連接的設備的IP地址。 為了獲得這樣的信息,我向該方法提供了WifiP2pManager.ConnectionInfoListener的實現,該方法由connectionInfoListener變量表示。 這是我實現WifiP2pManager.ConnectionInfoListener的代碼:
private WifiP2pManager.ConnectionInfoListener connectionInfoListener = new WifiP2pManager.ConnectionInfoListener() {
@Override
public void onConnectionInfoAvailable(WifiP2pInfo info) {
InetAddress deviceIP = info.groupOwnerAddress;
int port = servicesConnectionInfo.get(device);
ConnectThread connectThread = new ConnectThread(deviceIP, port, device);
connectThread.start();
“device”是我的BroadcastReceiver實現的實例變量,它現在並不重要。 相反,重要的是ConnectThread線程。 這是處理連接兩個設備之間的套接字所需的代碼的線程。 當我嘗試連接到檢測到的設備時,ConnectThread會在其run()方法中創建一個新的ChatConnection實例,將以前獲取的IP地址和端口號傳遞給此構造函數:
public ChatConnection(InetAddress srvAddress, int srvPort, String macAddress) throws IOException {
...
connSocket = new Socket(srvAddress, srvPort);
...
}
這就是問題發生的地方。 當我在我的物理設備上測試我的應用程序時,我得到的只是這個例外:
W/System.err: java.net.ConnectException: failed to connect to /192.168.49.1 (port 6770): connect failed: ECONNREFUSED (Connection refused)
當然,我也在第二台物理設備上安裝了我的應用程序,成功檢測到該應用程序並成功建立了Wi-Fi Direct連接。 但是,當涉及到這行代碼時:
connSocket = new Socket(srvAddress, srvPort);
拋出異常......我為這個問題的長度道歉,但我希望盡可能最清楚。 我真的非常感謝你提供任何幫助。
編輯:我忘了提到初始化ServerSocket的代碼。
ServerSocket在啟用Wi-Fi后立即啟動的線程中初始化。
也就是說,當WifiP2pBroadcastReceiver(擴展BroadcastReceiver的應用程序服務的內部類)捕獲WIFI_P2P_STATE_CHANGED_ACTION意圖時,它會檢查是否啟用了Wi-Fi,如果啟用,它將啟動ServerSocket所在的線程:
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equals(WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION)) {
int statoWiFi = intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1);
if (statoWiFi == WifiP2pManager.WIFI_P2P_STATE_ENABLED) {
mNsdService = new NsdProviderThread();
mNsdService.start();
}
ServerSocket在NsdProviderThread的run()方法中初始化:
public void run() {
...
try {
server = new ServerSocket(0);
} catch (IOException ex) {
return;
}
...
while (!Thread.currentThread().isInterrupted()) {
Socket clientSocket = null;
try {
clientSocket = server.accept();
} catch (IOException ex) {
break;
}
try {
ChatConnection chatConn = new ChatConnection(clientSocket);
synchronized (connections) {
connections.add(chatConn);
}
} catch (IOException ex) {
continue;
}
}
“server”是聲明為ServerSocket的NsdProviderThread的實例變量。
看起來您只需要在兩端使用正確的端口號。
你使用零,從文檔意味着:
端口號為0表示通常從臨時端口范圍自動分配端口號。
因此,在創建ServerSocket時,請確保它正在偵聽其他設備用於啟動連接的同一端口:
private static final int port = 6770;
//.....
try {
server = new ServerSocket(port);
} catch (IOException ex) {
ex.printStackTrace();
}
再次! 我終於設法讓我的應用程序正常運行。 這就是我所做的:
為了在建立Wi-Fi Direct連接后獲取設備的實際IP地址,我在“Utils”類中使用了我在這個項目中找到的這個功能(由原來的Android WiFiDirectdemo派生) :
public static String getLocalIPAddress() {
/*
* modified from:
*
* http://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/
*
* */
try {
for (Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces(); en.hasMoreElements();) {
NetworkInterface intf = en.nextElement();
for (Enumeration<InetAddress> enumIpAddr = intf.getInetAddresses(); enumIpAddr.hasMoreElements();) {
InetAddress inetAddress = enumIpAddr.nextElement();
String iface = intf.getName();
if(iface.matches(".*" +p2pInt+ ".*")){
if (inetAddress instanceof Inet4Address) { // fix for Galaxy Nexus. IPv4 is easy to use :-)
return getDottedDecimalIP(inetAddress.getAddress());
}
}
}
}
} catch (SocketException ex) {
Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex);
} catch (NullPointerException ex) {
Log.e("AndroidNetworkAddressFactory", "getLocalIPAddress()", ex);
}
return null;
}
“p2pInt”是在Utils類中聲明的私有靜態字符串costant:
private final static String p2pInt = "p2p-p2p0"
但是,在我的應用程序中,我更改了“p2p-wlan0”中的“p2p-p2p0”字符串,因為看起來我的Wi-Fi Direct設備的網絡接口具有(不同的)名稱。 我希望這可以幫助任何嘗試創建使用Wi-Fi Direct連接的應用程序的開發人員。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.