安卓開發SOCKET程式設計中幾種執行緒阻塞產生的原因與解決辦法
阿新 • • 發佈:2019-02-19
在使用socket程式設計中,有幾種情況會使執行緒產生阻塞。
1、解析DNS阻塞
當需要把一個域名解析為IP地址的時候,可用使用以下語句來獲得。使用下面API的時候,如果當前環境沒有網路,或者網路異常,將會使得解析失敗,getByName方法會丟擲異常,但是丟擲異常的時間大約在三四分鐘以後,時間太長。
InetAddress add = InetAddress.getByName(hostname);
String ip=add.getHostAddress();
解決方法(轉載):
package com.liang.client;
import java.net.InetAddress;
import java.net.UnknownHostException;
/**
* 自定義解析DNS伺服器類,解決斷網或異常情況下丟擲 UnknownHostException時間太長的問題。
* @author Liang
* 用法:
* 1、在需要解析的執行緒中建立DNSLookupThread執行緒物件
* DNSLookupThread dnsquery=new DNSLookupThread("liangruimi.vicp.net");
* 2、開啟執行緒
* dnsquery.start();
* 3、設定連線超時時間,這裡等待執行緒執行2s,即如果解析域名時間超過2s,則讀取結果,解析成功,返回的是IP地址,失敗返回的為空
* dnsquery.join(2000);
* 4、得到解析結果,如果為NULL,則表示解析失敗
* String ip = dnsquery.getIP();
*/
public class DNSLookupThread extends Thread {
private InetAddress addr;
private String hostname;
public DNSLookupThread(String hostname) {
this.hostname = hostname;
}
public void run() {
try {
InetAddress add = InetAddress.getByName(hostname);
set(add);
} catch (UnknownHostException e) {
}
}
private synchronized void set(InetAddress addr) {
this.addr = addr;
}
public synchronized String getIP() {
if (null != this.addr) {
return addr.getHostAddress();
}
return null;
}
}
2、連結阻塞
當需要與伺服器建立連線的時候,可以用以下方法來建立連線。使用如下方法構造socket物件會引起執行緒的長時間阻塞。因為如果埠無法連線,那麼丟擲異常的時間會很長,整個過程與上訴阻塞類似,大約需要三四分鐘。因此不建議用此方法來建立socket。
socket = new Socket(ipaAddress, 38134);//建立一個連結地址為IPAddress,埠38134為的物件。
解決方法:使用socket的Socket.connect(SocketAddress remoteAddr, int timeout)方法。
socket = new Socket();//建立一個沒有連線的socket物件
SocketAddress saddress = new InetSocketAddress(ip, 38134);//設定連線地址與埠
socket.connect(saddress, 10000);//第二個引數設定連線超時時間,這裡設定為10s。
if (socket.isConnected()) {
Log.i("liang", "socket已連線");//判斷連線是否成功。
}
3、獲取輸入流阻塞:
當需要獲取socket中輸入流資訊的時候可用使用以下方法,使用InputStreamReader方法將socket中InputStream流轉換為Reader類,並使用Reader類中的readLine方法獲得資訊。但是當呼叫readLine()方法的時候,如果輸入流中沒有任何資料的時候將一直等待,產生執行緒阻塞。
BufferedReader socketin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String socketinMessage = socketin.readLine();
解決方法:
在上述程式碼前設定超時時間
socket.setSoTimeout(50000);//此方法可以設定讀取輸入流超時時間,這裡設定為5s
BufferedReader socketin = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String socketinMessage = socketin.readLine();