2016-11-04 128 views
1

! 我正在开发一个Android应用程序,允许与附近已安装此应用程序的设备聊天。为了做到这一点,我使用Wi-Fi P2P API和网络服务发现来搜索附近的设备。 我已经编写了用于在服务启动的线程中搜索附近设备的代码。当检测到设备时,服务将它(通过广播意图)发送到显示到目前为止检测到的设备的活动。 检测到的设备被添加到recyclerView中,并且当用户按下其中一个时,必须建立到该设备的连接。 成功建立Wi-Fi Direct连接(即,WifiP2pManager.connect()方法成功),并捕获WIFI_P2P_CONNECTION_CHANGED_ACTION。 在广播接收机中,当这样的广播意图落入,下面的代码被执行:当通过Wi-Fi P2P使用网络服务发现时无法连接到Android设备每个人都可以使用网络服务发现

NetworkInfo networkInfo = (NetworkInfo) intent.getParcelableExtra(WifiP2pManager.EXTRA_NETWORK_INFO); 
      if (networkInfo.isConnected()) { 

       mManager.requestConnectionInfo(mChannel, connectionInfoListener); } 

随着requestConnectionInfo()方法我可以获取有关的连接,如装置I的IP地址的信息试图连接到。 为了获取这些信息,我提供了一个WifiP2pManager.ConnectionInfoListener实现,该实现由connectionInfoListener变量表示。 这是我实现WifiP2pManager.ConnectionInfoListener的代码:

​​

“设备”是我实现广播接收器的现在正好是不重要的实例变量。相反,重要的是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直连连接获得成功建立。但是,当涉及到这行代码:

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; 
      } 
     } 

“服务器” 是NsdProviderThread的一个实例变量声明为ServerSocket的。

+1

你需要一个ServerSocket接受来自其他设备.... –

+0

Socket连接我感谢您的评论。我刚刚编辑了我的问题,并添加了有关ServerSocket的更多信息。 – Nilio

回答

0

它看起来像你只需要使用两端正确的端口号。

您使用零,这从the documentation意味着:

的端口号0的装置的端口号是自动 分配,典型地从一个临时端口范围。

所以,当您创建的ServerSocket,确保其在同一端口上监听,其他设备用于发起连接:

private static final int port = 6770; 

//..... 

try { 
    server = new ServerSocket(port); 
} catch (IOException ex) { 
    ex.printStackTrace(); 
} 
+0

我尝试在ServerSocket中对端口号进行硬编码,如下所示: server = new ServerSocket(6770); 我在ChatConnection的构造函数中做了同样的事情: connSocket = new Socket(srvAddress,6770); 现在,当应用程序来到这行代码,异常不再抛出,但应用程序只是挂在那里(没有错误,没有例外),就像永远等待连接建立... – Nilio

0
再次

!我终于设法让我的应用程序工作。以下是我所做的:

  • 硬编码端口号;
  • 当你在ConnectionInfoListener执行群主地址,确保如果是在使用该设备的IP地址。如果不是,则将客户端套接字连接到组所有者地址;否则,使您的应用程序等待传入连接;
  • 尽快初始化的ServerSocket尽可能(例如,当应用程序启动时)。

为了获取设备的实际IP地址的Wi-Fi直连连接建立后,我用这个功能,我在this项目(通过原生Android WiFiDirectdemo派生)已找到在 “utils的” 类:

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 “p2p-wlan0中的”-p2p0“字符串“因为它看起来像我的设备的Wi-Fi Direct的网络接口具有该(不同)名称。 我希望这能帮助谁在试图创建一个使用Wi-Fi直接连接的应用程序,任何开发人员。