與ServerSocket對象相關的信息有兩個:綁定端口和綁定IP地址。綁定端口可以通過getLocalPort方法獲得。綁定IP地址可以通過getInetAddress方法獲得。
一、getLocalPort方法
getLocalPort方法的返回值可分為以下三種情況:
1.ServerSocket對象未綁定端口,getLocalPort方法的返回值為-1。
2.ServerSocket對象綁定了一個固定的端口,getLocalPort方法返回這個固定端口。
3.ServerSocket對象的綁定端口為0,getLocalPort方法返回一個隨機的端口(這類端口被稱為匿名端口)。
getLocalPort方法的定義如下:
public int getLocalPort()
getLocalPort方法主要是為這些匿名端口而准備的。下面的代碼演示了ServerSocket對象產生隨機端口的過程:
package server;
import java.net.*;
public class RandomPort
{
public static void main(String[] args) throws Exception
{
for (int i = 1; i <= 5; i++)
{
System.out.print("Random Port" + i + ":");
System.out.println(new ServerSocket(0).getLocalPort());
}
}
}
運行結果:
1.主動模式
在主動模式中,FTP服務器綁定了兩個端口:21和20 (這兩個端口是默認值,可以設成別的端口)。其中21端口負責客戶端和服務器之間的命令傳送。一開始,由客戶端主動連接服務端的21端口,並且向服務器發送相應的FTP命令。另外一個端口20是負責客戶端和服務端的數據傳送。但要注意,並不是客戶端主動連接服務端的20端口,而是在客戶端創建一個使用匿名端口的服務端連接(在Java中就是創建一個ServerSocket對象,並且綁定端口是0)。然後客戶端通過21端口將這個匿名端口通知服務端。最後,服務端主動連接客戶端的這個匿名端口(所以這種模式叫主動模式,就是服務器主動連接客戶端)。圖1描述主動模式的工作原理。
圖1 主動模式的工作原理
從圖1可以看出,在主動模式中,在傳送命令和數據時,建立連接的過程是相反的。也就是說,在傳送命令時,由客戶端主動連接服務器的21端口。而傳送數據時,由服務器主動連接客戶端的匿名端口。這種方式是FTP服務器最初的工作模式,但這種模式有很大的局限性。如客戶端通過代理上網,而且未做端口映射。在這種情況下,服務端是無法主動和客戶端建立連接的。因此,這就產生的另一種模式:被動模式。
2.被動模式
被動模式和主動模式在傳送命令的方式上是一樣的。它們的區別就在於數據的傳輸上。被動模式在建立命令傳輸通道後,服務端建立一個綁定到匿名端口的 ServerSocket對象。並通過命令傳輸通道將這個匿名端口通知客戶端,然後由客戶端主動連接服務端的這個匿名端口。這對於服務端就是被動的,因此,這種模式叫被動模式。圖2描述了被動模式的工作原理。
圖2 被動模式的工作原理
現在的大多數FTP客戶端軟件的默認工作模式都是被動模式。因此,這種模式可以克服防火牆等的限制,並且客戶端不需要有固定IP。但這種模式也有它的缺點,這就是在服務端要為客戶開大量的端口(大多數FTP服務器開的端口范圍是1024 ~ 5000,但有的服務器的范圍達到1024 ~ 65535)。這對於服務器來說存在著一定的安全隱患。因此,如果可能的話,最好還是采用主動模式。
二、getInetAddress方法
getInetAddress可以得到ServerSocket對象綁定的IP地址。如果ServerSocket對象未綁定IP地址,返回0.0.0.0。getInetAddress方法的定義如下:
public InetAddress getInetAddress()
下面的代碼演示了getInetAddress的使用方法:
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("192.168.18.100", 0));
System.out.println(serverSocket.getInetAddress().getHostAddress());
運行結果:
192.168.18.100
三、getLocalSocketAddress方法
這個方法其實是將getLocalPort和getInetAddress方法的功能集成到了一起。也就是說,使用 getLocalSocketAddress方法可以同時得到綁定端口和綁定IP地址。這個方法返回了一個SocketAddress對象。 SocketAddress類是一個抽象類,要想分別得到端口和IP地址,必須將SocketAddress對象轉換成 InetSocketAddress對象(InetSocketAddress類是從SocketAddress類繼承的)。 getLocalSocketAddress方法的定義如下:
public SocketAddress getLocalSocketAddress()
下面的代碼演示了getLocalSocketAddress的使用方法。
ServerSocket serverSocket = new ServerSocket();
serverSocket.bind(new InetSocketAddress("192.168.18.100", 1234));
System.out.println(serverSocket.getLocalSocketAddress());
InetSocketAddress nsa = (InetSocketAddress)serverSocket.getLocalSocketAddress();
System.out.println( nsa.getAddress().getHostAddress());
System.out.println( nsa.getPort());
運行結果:
/192.168.18.100:1234
192.168.18.100
1234