大家好! 我正在开发一款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 :(得分:0)
看起来您只需要在两端使用正确的端口号。
您使用的是零,the documentation表示:
端口号为0表示端口号是自动的 通常从短暂的港口范围分配。
因此,在创建ServerSocket时,请确保它正在侦听其他设备用于启动连接的同一端口:
private static final int port = 6770;
//.....
try {
server = new ServerSocket(port);
} catch (IOException ex) {
ex.printStackTrace();
}
答案 1 :(得分:0)
又来了!我终于设法让我的应用运行起来了。这就是我所做的:
为了在建立Wi-Fi Direct连接后获取设备的实际IP地址,我已经使用了我在this项目中找到的这个功能(由" 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;
}
&#34; p2pInt&#34;是在Utils类中声明为:
的私有静态字符串costantprivate final static String p2pInt = "p2p-p2p0"
然而,在我的应用中,我已经改变了&#34; p2p-p2p0&#34;字符串在&#34; p2p-wlan0&#34;因为看起来我的Wi-Fi Direct设备的网络接口有这个(不同的)名称。 我希望这可以帮助任何尝试创建使用Wi-Fi Direct连接的应用的开发者。