Socket構造方法和Socket的設置與異常
本文將介紹Socket的構造方法和Socket的相關屬性設置與異常處理
- 構造Socket
- 設置等待超時時間
- 設置服務器地址
- 設置客戶端地址
- 客戶端連接服務器可能出現的異常
構造Socket
Socket的構造方法有如下幾種重載方式:
Socket();
Socket(InetAddress address, int port)
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
Socket(Proxy proxy)
Socket(SocketImpl impl)
Socket(String host, int port)
Socket(String host, int port, InetAddress localAddr, int localPort)
除了第一個構造器外,其他構造器都會嘗試與服務器建立連接,如果連接成功返回Socket對象;如果因爲某些原因連接失敗,就拋出IOException。
如下代碼掃描主機上從1到1024之間的端口,判斷這些端口是否已經被服務器程序監聽。
public class PortScanner {
public static void main(String[] args) {
String host = "localhost";
new PortScanner().scan(host);
}
public void scan(String host){
Socket socket = null;
for(int i=0;i<1024;i++){
try {
socket = new Socket(host, i);
System.out.println("There is a server on port "+i);
} catch (IOException e) {
System.out.println("Can't connect to port "+i);
}finally{
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
}
設置等待建立連接的超時時間
使用不帶參數的構造方法,設置socket連接超時時間:
Socket socket = new Socket();
SocketAddress endPoint = new InetSocketAddress("localhost", 8000);
socket.connect(endPoint, 60000);
以上代碼表示用於連接本機上監聽的8000端口,等待連接的最長時間爲1分鐘。如果在1分鐘內連接成功,則connect()方法順利返回;如果在1分鐘之內出現異常,則拋出異常;如果超過1分鐘,既沒有連接成功,也沒有拋出異常,那麼會拋出SocketTimeoutException
。socket. connect(SocketAddress endpoint, int timeout);
負責連接服務器,參數endpoint指定服務器地址,參數timeout設定超時時間,以毫秒爲單位。如果參數timeout爲0,表示永遠不超時。
設置服務器地址
Socket的構造方法中,除了第一個不帶參數的構造方法,其他構造方法都需要指定服務器地址,包括服務器的IP或主機名,以及端口:
Socket(InetAddress address, int port)
Socket(String host, int port)
InetAddress類表示服務器的IP地址,InetAddress提供了很多靜態方法:
// 返回本地主機的IP地址
InetAddress.getLocalHost();
// 返回代表10.202.164.65的IP地址
InetAddress.getByName("10.202.164.65");
// 返回域名爲'www.csdn.net'的ip地址
InetAddress.getByName("www.csdn.net");
設置客戶端的地址:
默認情況下,客戶端的IP地址來自於客戶端程序所在的主機,客戶端的端口則由操作系統隨機分配。但是Socket類還是提供了構造方法允許顯式地設置客戶端的IP和端口:
//參數localAddr和localPort用來設置客戶端的IP和端口。
Socket(InetAddress address, int port, InetAddress localAddr, int localPort)
Socket(String host, int port, InetAddress localAddr, int localPort)
客戶端連接服務器可能拋出的異常
當Socket構造方法請求連接服務器時,可能會拋出下面的異常:
• UnknownHostException:如果無法識別主機的名字或IP地址,就會拋出這種異常
• ConnectException:如果沒有服務器進程監聽指定的端口,或者服務器拒絕連接,就會拋出這種異常。
• SocketTimeoutException:如果等待連接超時,就會拋出這種異常。
• BindException:如果無法把Socket對象與指定的本地IP地址或端口綁定,就會拋出這種異常。
通過下面測試類爲例,演示拋出異常的原因。
public class ConnectTester {
public static void main(String[] args) {
String host = "www.csdn.net";
int port = 12312;
new ConnectTester().connect(host, port);
}
public void connect(String host,int port){
SocketAddress remoteAddress = new InetSocketAddress(host, port);
Socket socket = null;
String result = null;
try{
socket = new Socket();
long start = System.currentTimeMillis();
socket.connect(remoteAddress,1000);
long end = System.currentTimeMillis();
result = (end-start)+"ms";
}catch(BindException bindException){
result = "BindException,Socket對象與指定的本地IP地址或端口綁定,異常";
}catch (UnknownHostException unknownHostException) {
result = "UnknownHostException,無法識別的主機";
}catch (ConnectException connectException) {
result = "ConnectException,連接被拒絕";
}catch (SocketTimeoutException socketTimeoutException) {
result = "SocketTimeoutException,連接超時";
}catch(IOException e){
result = "IOException,連接失敗";
}finally{
if(socket!=null){
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
System.out.println(remoteAddress+" : "+result);
}
}
• 拋出UnknownHostException情況:
如果無法識別主機的名字或IP地址,就會拋出這種異常。例如:host爲:’ somehost11’。Socket的connect方法就會拋出UnknownHostException異常。
• 拋出ConnectException的情況:
在以下兩種情況會拋出ConnectException。
1) 沒有服務器進程監聽指定的端口。例如:host爲 ‘localhost’ port爲 12321 。如果本機的12321端口沒有被任何進程監聽,則Socket連接方法會拋出ConnectException。
2) 服務器進程拒絕連接。介紹服務器進程拒絕客戶的連接請求的情形。如下示例代碼,一個簡單的服務程序ServerSocket構造方法中的第二個參數表示請求隊列的長度。如果隊列的請求已滿,服務器就會拒絕其餘的請求。拋出ConnectException
public class SimplServer {
public static void main(String[] args) throws Exception{
ServerSocket serverSocket = new ServerSocket(8888, 2);
Thread.sleep(3600000);
}
}
public class SimpleClient {
public static void main(String[] args) throws Exception{
String host = "localhost";
int port = 8888;
Socket s1 = new Socket(host, port);
System.out.println("第一次連接成功");
Socket s2 = new Socket(host, port);
System.out.println("第二次連接成功");
Socket s3 = new Socket(host, port);
System.out.println("第三次連接成功");
}
}
• 拋出SocketTimeoutException的情形
如果客戶端連接超時,就會拋出這種異常。修改 socket.connect(remoteAddress, 1);
由原來的1000毫秒修改爲1毫秒,這樣增加了超時的可能性。
• 拋出BindException的情形:
將代碼
socket = new Socket();
socket.connect(remoteAddress, 1000);
修改爲:
socket = new Socket();
socket.bind(new InetSocketAddress(InetAddress.getByName("222.34.5.6"), 5678));
socket.connect(remoteAddress, 1000);
修改後的代碼試圖把Socket的本地IP地址設爲222.34.5.6,把本地端口設置爲5678。如果本機不具有該IP,或者端口被佔用,那麼就會出現BindException。
歡迎關注微信公衆號 在路上的coder
每天分享優秀的Java技術文章!
掃描二維碼關注: