最近在重構(gòu)藍(lán)牙配網(wǎng)的時(shí)候抓谴,發(fā)現(xiàn)了一個(gè)問(wèn)題暮蹂,在完成wifi賬號(hào)密碼傳輸后,設(shè)備連接wifi齐邦,并將自己的ipv4地址在局域網(wǎng)中廣播出來(lái)椎侠,android手機(jī)在收到廣播后,可以得到設(shè)備在局域網(wǎng)中的ip地址措拇,從而進(jìn)行下一步的操作
但是在android手機(jī)接收局域網(wǎng)廣播的過(guò)程中,代碼出現(xiàn)了問(wèn)題慎宾,一般來(lái)說(shuō)丐吓,使用DatagramSocket
是這樣的:
DatagramSocket datagramSocket;
String boxIPV4 = null;
int port = 3005;
byte[] message = new byte[1024];
try {
// 建立Socket連接
datagramSocket = new DatagramSocket(port);
DatagramPacket dp = new DatagramPacket(message, message.length);
// 準(zhǔn)備接收數(shù)據(jù)
// datagramSocket.setSoTimeout(165000);
datagramSocket.receive(dp);
boxIPV4 = new String(dp.getData(), 0, dp.getLength(), "UTF-8");
} catch (Exception e) {
e.printStackTrace();
}
如果不設(shè)置超時(shí)時(shí)間,那線程就會(huì)一直堵在datagramSocket.receive(datagramPacket)
這行趟据,但是如果設(shè)置了超時(shí)時(shí)間券犁,那如果是用戶自己取消呢,所以就需要手動(dòng)取消接收廣播汹碱,像下面代碼一樣:
try {
if (datagramSocket != null && !datagramSocket.isClosed()) {
datagramSocket.disconnect();
datagramSocket.close();
}
} catch (Exception e) {
e.printStackTrace();
}
但是奇怪的是粘衬,即使執(zhí)行了上述的代碼,socket也沒(méi)有從receive方法處跳出來(lái)咳促,反而出現(xiàn)了anr稚新,查看了disconnect()
以及close()
兩個(gè)方法的代碼后,才明白跪腹,原來(lái)disconnect()
方法加了synchronized
關(guān)鍵字褂删,而receive()
方法也同樣加了一個(gè)大大的synchronized
代碼塊
// DatagramSocket.java
public void disconnect() {
synchronized (this) {
if (isClosed())
return;
if (connectState == ST_CONNECTED) {
impl.disconnect ();
}
connectedAddress = null;
connectedPort = -1;
connectState = ST_NOT_CONNECTED;
explicitFilter = false;
}
}
public synchronized void receive(DatagramPacket p) throws IOException {
synchronized (p) {
if (!isBound())
bind(new InetSocketAddress(0));
// BEGIN Android-changed
if (pendingConnectException != null) {
throw new SocketException("Pending connect failure", pendingConnectException);
}
// END Android-changed
...
}
}
receive方法還在等待接收數(shù)據(jù),而disconnect方法又要斷開(kāi)連接冲茸,導(dǎo)致死鎖屯阀,所以出現(xiàn)了anr,所以這里需要先close轴术,然后再disconnect才行
try {
if (datagramSocket != null && !datagramSocket.isClosed()) {
datagramSocket.close();
datagramSocket.disconnect();
}
} catch (Exception e) {
e.printStackTrace();
}
調(diào)整了close和disconnect的順序后难衰,就可以順利跳出receive方法了
網(wǎng)上也搜到了一篇類(lèi)似的文章:
https://blog.csdn.net/qq_35522272/article/details/54314289