構造 ServerSocket ServerSocket 的構造方法有以下幾種重載形式 ServerSocket() throws IOException ServerSocket(int port) throws IOException ServerSocket(int port, int bac ...
構造 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. 綁定埠
除了第 1 個不帶參數的構造方法,其他構造方法都會使伺服器與特定埠綁定,由參數 port 指定,無法綁定則拋出 IOException,一般是因為埠已經被其他服務占用,或者沒有足夠的許可權去綁定
如果把參數 port 設為 0,則表示由操作系統為伺服器分配一個任意的可用埠,也被稱為匿名埠。對於多數伺服器,會使用明確的埠,而不會使用匿名埠,因為客戶程式需要事先知道伺服器的埠,才能方便地訪問伺服器
ServerSocket(int port) throws IOException
2. 設定客戶連接請求隊列的長度
當伺服器進程運行時,可能會同時監聽到多個客戶的連接請求,管理客戶連接請求的任務是由操作系統來完成的。操作系統把這些連接請求存儲在一個先進先出的隊列中,許多操作系統都限定了隊列的最大長度,一般為 50。當隊列中的連接請求達到了隊列的最大長度時,伺服器進程所在的主機會拒絕新的連接請求,只有當伺服器進程通過 ServerSocket 的 accept()
方法從隊列中取出連接請求,使隊列騰出空位,隊列才能繼續加入新的連接請求
ServerSocket 構造方法的 backlog 參數用來顯式設置連接請求隊列的長度,它將覆蓋操作系統限定的隊列的最大長度。值得註意的是,在以下幾種情況中,仍然會採用操作系統限定的隊列的最大長度:
- backlog 參數的值大於操作系統限定的隊列的最大長度
- backlog 參數的值小於或等於 0
- 在 ServerSocket 構造方法中沒有設置 backlog 參數
3. 設定綁定的 IP 地址
ServerSocket 的第 4 個構造方法有個 bindAddr 參數,它顯式地指定伺服器要綁定的 IP 地址,適用於具有多個 IP 地址的主機
接收和關閉與客戶的連接
ServerSocket 的 accept()
方法從連接請求隊列中取出一個客戶的連接請求,然後創建與客戶連接的 Socket 對象,井將它返回。如果隊列中沒有連接請求,accept()
方法就會一直等待下去。接下來,伺服器從 Socket 對象獲得輸入流和輸出流,就能與客戶交換數據了
以下代碼展示了單線程伺服器採用的通信流程
public void service() {
while (true) {
Socket socket = null;
try {
// 從連接請求隊列中取出一個連接
socket = serverSocket.accept();
System.out.printin("New connection accepted " + socket,getInetAddress() + ":" + socket.getPort());
//接收和發送數據
...
} catch (IOException e) {
// 這隻是與單個客戶通信時遇到的異常,可能是由於客戶端過早斷開連接引起的
// 這種異常不應該中斷整個while迴圈
e.printStackTrace();
} finally {
try {
// 與一個客戶通信結束後,要關閉Socket
if(socket != null) socket.close();
}catch (IOException e) {
e.printStackTrace();
}
}
}
}
關閉 ServerSocket
ServerSocket 的 close()
方法使伺服器釋放占用的埠,並且斷開與所有客戶的連接
ServerSocket 的 isClosed()
方法判斷 ServerSocket 是否關閉,只有執行了 ServerSocket 的 close()
方法,isClosed()
方法才返回 true,否則即使 ServerSocket 還有沒有和特定埠綁定,該方法也會返回 false
ServerSocker 的 isBound()
方法判斷 ServerSocket 是否已經與一個埠綁定,只要 ServerSocket 已經與一個埠綁定,即使它已經被關閉,該方法也會返回 true
如果需要判斷一個 ServerSocket 是否已經與特定埠綁定,並且還沒有被關閉,則可以採用以下方式
boolean isOpen = serverSocket.isBound() && !serverSocket.isClosed();
獲取 ServerSocket 的信息
ServerSocket 的以下兩個 get 方法分別用於獲得伺服器綁定的 IP 地址,以及綁定的埠
public InetAddress getInetAddress()
publlc int getLocalPort()
ServerSocket 選項
1. SO_TIMEOUT
表示 ServerSocket 的 accept()
方法等待客戶連接的超時時間,以 ms 為單位。如果 SO_TIMEOUT 的值為 0 則表示永遠不會超時,這是 SO_TIMEOUT 的預設值
public void setSoTimeout(int timeout) throws SocketException
public int getSoTimeout() throws IOException
2. SO_REUSEADDR
這個選項與 Socket 的 SO_REUSEADDR 選項相同,決定如果網路上仍然有數據向舊的 ServerSocket 傳輸,那麼是否允許新的 ServerSocket 綁定到與舊的 ServerSocket 同樣的埠
public void setResuseAddress(boolean on) throws SocketException
public boolean getResuseAddress() throws SocketException
3. SO_RCVBUF
表示伺服器端的用於接收數據的緩衝區的大小,以位元組為單位
public void setReceiveBufferSize(int size) throws SocketException
public int getReceiveBufferSize() throws SocketException
4. 設定連接時間、延遲和帶寬的相對重要性
該方法的作用與 Socket 的 setPerformancePreferences()
方法的作用相同