在客戶/服務器通信模式中,服務器端需要創建監聽特定端口的ServerSocket,ServerSocket負責接收客戶連接請求。
ServerSocket的構造方法有以下幾種重載形式:
ServerSocket()throws IOException
ServerSocket(int port) throws IOException
ServerSocket(int port, int backlog) throws IOException
ServerSocket(int port, int backlog, InetAddress bindAddr) throws IOException
在以上構造方法中,參數port指定服務器要綁定的端口(服務器要監聽的端口),參數backlog指定客戶連接請求隊列的長度,參數bindAddr指定服務器要綁定的ip地址。
注意點:1. 如果端口被占用或者沒有權限使用某些端口會拋出BindException錯誤。譬如1~1023的端口需要管理員才擁有權限綁定。2. 如果設置端口為0,則系統會自動為其分配一個端口;3. bindAddr用于綁定服務器IP,為什么會有這樣的設置呢,譬如有些機器有多個網卡。4. ServerSocket一旦綁定了監聽端口,就無法更改。ServerSocket()可以實現在綁定端口前設置其他的參數。
除了第一個不帶參數的構造方法以外,其他構造方法都會使服務器與特定端口綁定,該端口由參數port指定。
例如,以下代碼創建了一個與80端口綁定的服務器:
1 ServerSocket serverSocket = new ServerSocket(80);
如果運行時無法綁定到80端口,以上代碼會拋出IOException,更確切地說,是拋出BindException,它是IOException的子類。
BindException一般是由以下原因造成的:
1.端口已經被其他服務器進程占用;
2.在某些操作系統中,如果沒有以超級用戶的身份來運行服務器程序,那么操作系統不允許服務器綁定到1~1023之間的端口。
如果把參數port設為0,表示由操作系統來為服務器分配一個任意可用的端口。由操作系統分配的端口也稱為匿名端口。對于多數服務器,會使用明確的端口,而不會使用匿名端口,因為客戶程序需要事先知道服務器的端口,才能方便地訪問服務器。
當服務器進程運行時,可能會同時監聽到多個客戶的連接請求。
例如,每當一個客戶進程執行以下代碼:
1 Socket socket = new Socket("127.0.0.1",80);
管理客戶連接請求的任務是由操作系統來完成的。操作系統把這些連接請求存儲在一個先進先出的隊列中。許多操作系統限定了隊列的最大長度,一般為50。當隊列中的連接請求達到了隊列的最大容量時,服務器進程所在的主機會拒絕新的連接請求。只有當服務器進程通過ServerSocket的accept()方法從隊列中取出連接請求,使隊列騰出空位時,隊列才能繼續加入新的連接請求。
對于客戶進程,如果它發出的連接請求被加入到服務器的隊列中,就意味著客戶與服務器的連接建立成功,客戶進程從Socket構造方法中正常返回。如果客戶進程發出的連接請求被服務器拒絕,Socket構造方法就會拋出ConnectionException。
ServerSocket構造方法的backlog參數用來顯式設置連接請求隊列的長度,它將覆蓋操作系統限定的隊列的最大長度。值得注意的是,在以下幾種情況中,仍然會采用操作系統限定的隊列的最大長度:
1.backlog參數的值大于操作系統限定的隊列的最大長度;
2.backlog參數的值小于或等于0;
3.在ServerSocket構造方法中沒有設置backlog參數。
如果主機只有一個IP地址,那么默認情況下,服務器程序就與該IP地址綁定。ServerSocket的第4個構造方法ServerSocket(int port, int backlog, InetAddress bindAddr)有一個bindAddr參數,它顯式指定服務器要綁定的IP地址,該構造方法適用于具有多個IP地址的主機。假定一個主機有兩個網卡,一個網卡用于連接到Internet, IP地址為222.67.5.94,還有一個網卡用于連接到本地局域網,IP地址為192.168.3.4。如果服務器僅僅被本地局域網中的客戶訪問,那么可以按如下方式創建ServerSocket:
ServerSocket serverSocket=new ServerSocket(8000,10,InetAddress.getByName ("192.168.3.4"));
ServerSocket的accept()方法從連接請求隊列中取出一個客戶的連接請求,然后創建與客戶連接的Socket對象,并將它返回。如果隊列中沒有連接請求,accept()方法就會一直等待,直到接收到了連接請求才返回。
接下來,服務器從Socket對象中獲得輸入流和輸出流,就能與客戶交換數據。當服務器正在進行發送數據的操作時,如果客戶端斷開了連接,那么服務器端會拋出一個IOException的子類SocketException異常。
ServerSocket的close()方法使服務器釋放占用的端口,并且斷開與所有客戶的連接。當一個服務器程序運行結束時,即使沒有執行ServerSocket的close()方法,操作系統也會釋放這個服務器占用的端口。因此,服務器程序并不一定要在結束之前執行ServerSocket的close()方法。
ServerSocket的isClosed()方法判斷ServerSocket是否關閉,只有執行了ServerSocket的close()方法,isClosed()方法才返回true;否則,即使ServerSocket還沒有和特定端口綁定,isClosed()方法也會返回false。
ServerSocket的isBound()方法判斷ServerSocket是否已經與一個端口綁定,只要ServerSocket已經與一個端口綁定,即使它已經被關閉,isBound()方法也會返回true。
如果需要確定一個ServerSocket已經與特定端口綁定,并且還沒有被關閉,則可以采用以下方式:
1 boolean isOpen = serverSocket.isBound() && !serverSocket.isClosed();
ServerSocket的以下兩個get方法可分別獲得服務器綁定的IP地址,以及綁定的端口:
public InetAddress getInetAddress() //獲取服務IP地址
public int getLocalPort() //獲取服務器綁定的端口
ServerSocket有以下3個選項。
SO_TIMEOUT:表示等待客戶連接的超時時間。
SO_REUSEADDR:表示是否允許重用服務器所綁定的地址。
SO_RCVBUF:表示接收數據的緩沖區的大小。
具體用法請參見一下個課件,謝謝!
java serversocket參數詳解 http://www.49028c.com/QQ5941/p/4869906.html
來源:
http://www.49028c.com/rond/p/3565113.html
http://www.51cto.com/specbook/11/40196.htm
新聞熱點
疑難解答