歡迎您光臨本站 註冊首頁

在上一篇文章中我們討論了Socket類的基本用法,並給出的例子中使用Socket類連接伺服器時使用了一種最簡單的連接方式,也就是通過IP和埠號來連接伺服器.而為了使連接伺服器的方式更靈活,Socket類不僅可以通過自身的構造方法連接伺服器,而且也可以通過connect方法來連接資料庫.

一、通過構造方法連接伺服器

我們可以通過6個重載構造函數以不同的方式來連接伺服器.這6個重載的構造函數可以分為兩類:

1. 自動選擇IP

這種方式是最常用的.所謂自動選擇IP,是指當本機有多塊網卡或者在一個網卡上綁定了多個IP時,Socket類會自動為我們選擇一個可用的IP.在上述6個構造方法中有4個是使用這種方法來連接伺服器的.

<!——[if !supportLists]——>(1) <!——[endif]——>public Socket(String host, int port)

這是最常用的構造方法,在前面的例子中就是使用的這個構造方法.在使用時只需要提供一個字元串類型的IP或域名以及一個整型的埠號即可.在這個構造方法中可能會拋出兩個錯誤:UnknownHostException和IOException.發生第一個錯誤的原因是我們提供的host並不存在或不合法,而其它的錯誤被歸為IO錯誤.因此,這個構造方法的完整定義是:

public Socket(String host, int port) throws UnknownHostException, IOException

(2) public Socket(InetAddress inetaddress, int port)

這個構造方法和第一種構造方法類似,只是將字元串形式的host改為InetAddress對象類型了.在這個構造方法中之要使用InetAddress類主要是考慮到在程序中可能需要使用Socket類多次連接同一個IP或域名,這樣使用InetAddress類的效率比較高.另外,在使用字元串類型的host連接伺服器時,可能會發生兩個錯誤,但使用InetAddress對象來描述host,只會發生IOException錯誤,這是當你將IP或域名傳給InetAddress時,InetAddress會自動檢查這個IP或域名,如果這個IP或域名無效,那麼InetAddress就會拋出UnknownHostException錯誤,而不會由Socket類的構造方法拋出.因此,這個構造方法的完整定義是:

public Socket(InetAddress inetaddress, int port) throws IOException

(3) public Socket(String host, int port, boolean stream)

這個構造方法和第一種構造方法差不多,只是多了一個boolean類型的stream參數.如果這個stream為true,那麼這個構造方法和第一種構造方法完全一樣.如果stream為false,則使用UDP協議建立一個UDP連接(UDP將在下面的章節詳細討論,在這裡只要知道它和TCP最大的區別是UDP是面向無連接的,而TCP是面向有連接的),也許是當初Sun的開發人員在編寫Socket類時還未考慮編寫處理UDP連接的DatagramSocket類,才將建立UDP連接的功能加入到Socket類中,不過Sun在後來的JDK中加入了DatagramSocket類,,這個構造方法就沒什麼用了,因此,Sun將其設為了Deprecated標記,也就是說,這個構造方法在以後的JDK版本中可以會被刪除.其於以上原因,在使用Java編寫網路程序時,盡量不要使用這個構造方法來建立UDP連接.

(4) public Socket(InetAddress inetaddress, int port, boolean flag)

這個構造方法和第三種構造方法的flag標記的含義一樣,也是不建議使用的.

下面的代碼演示上述4種構造方法的使用:

package mysocket;

import java.net.*;
import java.io.*;


public class MoreConnection
{
private static void closeSocket(Socket socket)
{
if (socket != null)
try
{
socket.close();
}
catch (Exception e) { }
}

public static void main(String[] args)
{
Socket socket1
= null, socket2 = null, socket3 = null, socket4 = null;
try
{
// 如果將www.ptpress.com.cn改成其它不存在的域名,將拋出UnknownHostException錯誤
// 測試public Socket(String host, int port)

socket1 = new Socket("www.ptpress.com.cn", 80);
System.out.println(
"socket1連接成功!");
// 測試public Socket(InetAddress inetaddress, int port)
socket2 = new Socket(InetAddress.getByName("www.ptpress.com.cn"), 80);
System.out.println(
"socket2連接成功!");

// 下面的兩種建立連接的方式並不建議使用
// 測試public Socket(String host, int port, boolean stream)
socket3 = new Socket("www.ptpress.com.cn", 80, false);
System.out.println(
"socket3連接成功!");
// 測試public Socket(InetAddress inetaddress, int i, boolean flag)

socket4 = new Socket(InetAddress.getByName("www.ptpress.com.cn"), 80, false);
System.out.println(
"socket4連接成功!");
}
catch (UnknownHostException e)
{
System.out.println(
"UnknownHostException 被拋出!");
}
catch (IOException e)
{
System.out.println(
"IOException 被拋出!");
}
finally
{
closeSocket(socket1);
closeSocket(socket2);
closeSocket(socket3);
closeSocket(socket4);
}
}
}

在上面代碼中的通過finally關閉了被打開的Socket連接,這是一個好習慣.只有在將關閉Socket連接的代碼寫在finally里,無論是否出錯,都會執行這些代碼.但要注意,在關閉Socket連接之前,必須檢查Socket對象是否為null,這是錯誤很可能在建立連接時發生,這樣Socket對象就沒有建立成功,也就用不著關閉了.

1. 手動綁定IP

當本機有多個IP時(這些IP可能是多塊網卡上的,也可能是一塊網卡上綁定的多個IP),在連接伺服器時需要由客戶端確定需要使用哪個IP.這樣就必須使用Socket類的另外兩個構方法來處理.下面讓我們來看看這兩個構造方法是如何來使用特定的IP來連接伺服器的.

public Socket(String host, int port, InetAddress inetaddress, int localPort)

這個構造方法的參數分為兩部分,第一部分為前兩個參數:host和port,它們分別表示要連接的伺服器的IP和埠號.第二部分為後兩個參數:inetaddress和localPort.其中inetaddress則表示要使用的本地的IP,而localPort則表示要綁定的本地埠號.這個localPort這以設置為本機的任何未被綁定的埠號.如果將localPort的值設為0,java將在1024到65,535之間隨即選擇一個未綁定的埠號.因此,在一般情況下將localPort設為0.

public Socket(InetAddress inetaddress, int port, InetAddress inetaddress1, int localPort)

這個構造方法和第一個構造方法基本相同,只是將第一個參數host換成了inetaddress.其它的使用方法和第一個構造方法類似.

在下面的代碼中將使用這兩個構造方法來做一個實驗.我們假設有兩台計算機:PC1和PC2.PC1和PC2各有一塊網卡.PC1綁定有兩個IP:192.168.18.252和200.200.200.200.PC2綁定有一個IP:200.200.200.4.PC1和PC2的子網掩碼都是255.255.255.0.而PC1的默認網關為:192.168.28.254.下面的代碼需要在PC1上運行.

package mysocket;

import java.net.*;

public class MoreConnection1
{
public static void main(String[] args)
{
try
{
InetAddress localAddress1
= InetAddress.getByName("200.200.200.200");
InetAddress localAddress2
= InetAddress.getByName("192.168.18.252");

// 如果將localAddress1改成localAddress2,socket1無法連接成功
Socket socket1 = new Socket("200.200.200.4", 80, localAddress1, 0);
System.out.println(
"socket1連接成功!");
Socket socket2
= new Socket("www.ptpress.com.cn", 80, localAddress2, 0);
System.out.println(
"socket2連接成功!");
// 下面的語句將拋出一個IOException錯誤
Socket socket3 = new Socket("www.ptpress.com.cn", 80, localAddress1, 0);
System.out.println(
"socket3連接成功!");
socket1.close();
socket2.close();
socket3.close();
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}

運行上面代碼的輸出結果如下:

socket1連接成功!
socket2連接成功
!
Connection timed out: connect

從上面的輸出結果可以看出,socket1和socket2已經連接成功,而socket3並未連接成功.從常式4-8可以看出,socket1在連接時使用localAddress1綁定到了200.200.200.200上,而PC2的IP是200.200.200.4,因此,socket1所使用的IP和PC2的IP在同一個網段,socket1可以連接成功.如果將localAddress1改成localAddress2后,socket1將無法連接成功.另外兩個Socket連接socket2和socket3是通過Internet連接www.ptpress.com.cn.它們所不同的是socket2綁定的是192.168.18.252,而socket3綁定的是200.200.200.200.它們執行的結果是socket2可以連接成功,而socket3連接失敗.這是socket2所綁定的IP和PC1的默認網關192.168.18.254在同一個網段,因此,socket2可以連接到Internet.而socket3所綁定的IP和PC1的IP不在同一個網段,因此,socket3將無法連接到Internet.

二、通過connect方法連接伺服器

Socket類不僅可以通過構造方法直接連接伺服器,而且還可以建立未連接的Socket對象,並通過connect方法來連接伺服器.Socket類的connect方法有兩個重載形式:

1. public void connect(SocketAddress endpoint) throws IOException

Socket類的connect方法和它的構造方法在描述伺服器信息(IP和埠)上有一些差異.在connect方法中並未象構造方法中以字元串形式的host和整數形式的port作為參數,而是直接將IP和埠封裝在了SocketAddress類的子類InetSocketAddress中.可按如下形式使用這個connect方法:

Socket socket = new Socket();
socket.connect(
new InetSocketAddress(host, port));

2. public void connect(SocketAddress endpoint, int timeout) throws IOException

這個connect方法和第一個connect類似,只是多了一個timeout參數.這個參數表示連接的超時時間,單位是毫秒.使用timeout設為0,則使用默認的超時時間.

在使用Socket類的構造方法連接伺服器時可以直接通過構造方法綁定本地IP,而connect方法可以通過Socket類的bind方法來綁定本地IP.常式4-9演示如何使用connect方法和bind方法.

package mysocket;

import java.net.*;

public class MoreConnection2
{
public static void main(String[] args)
{
try
{
Socket socket1
= new Socket();
Socket socket2
= new Socket();
Socket socket3
= new Socket();
socket1.connect(
new InetSocketAddress("200.200.200.4", 80));
socket1.close();
System.out.println(
"socket1連接成功!");
/*
將socket2綁定到192.168.18.252將產生一個IOException錯誤
socket2.bind(new InetSocketAddress("192.168.18.252", 0));
*/
socket2.bind(
new InetSocketAddress("200.200.200.200", 0));
socket2.connect(
new InetSocketAddress("200.200.200.4", 80));

socket2.close();
System.out.println(
"socket2連接成功!");


socket3.bind(
new InetSocketAddress("192.168.18.252", 0));
socket3.connect(
new InetSocketAddress("200.200.200.4", 80), 2000);
socket3.close();
System.out.println(
"socket3連接成功!");
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}

上面的代碼的輸出結果為:

socket1連接成功!
socket2連接成功
!
Connection timed out: connect

在上面代碼中的socket3連接伺服器時為其設置了超時時間(2000毫秒),因此,socket3在非常短的時間就拋出了IOException錯誤.


[火星人 ] Java網路編程從入門到精通(14):多種多樣的建立網路連接的方式已經有294次圍觀

http://coctec.com/docs/java/show-post-61638.html