1. 程式人生 > >Java網路程式設計——Socket通訊

Java網路程式設計——Socket通訊

  • Socket通訊基於TCP/IP協議。TCP/IP通訊協議是一種可靠的網路協議,它在通訊的兩端各建立一個Socket,從而在通訊的兩端之間形成網路虛擬鏈路。一旦建立了虛擬的網路鏈路,兩端的程式就可以通過網路虛擬鏈路進行通訊。
  • Java對基於TCP/IP協議的網路通訊提供了良好的封裝,Java使用Socket物件來代表兩端的通訊埠,並通過Socket產生IO流來進行網路通訊。

TCP/IP協議基礎介紹

1. IP協議

  • IP協議是Internet上使用的一個關鍵協議,全稱是Internet Protocol,即Internet協議,簡稱IP協議。
  • 通過使用IP協議,從而使Internet成為一個允許連線不同型別的計算機和不同作業系統的網路。
  • IP協議保證計算機能傳送和接收分組資料。IP協議負責將訊息從一個主機傳送到另一個主機,訊息在傳送過程中被分割成一個個的小包。

IP協議只是保證了計算機之間可以傳送和接收資料,但IP協議並不能解決資料分組在傳輸過程中可能出現的異常情況。此時需要通過TCP協議來提供可靠並且無差錯的通訊服務。

2. TCP協議

  • TCP協議被稱作一種端對端協議。當一臺計算機需要與另一臺遠端計算機連線時,TCP協議會讓它們建立一個連線,即用於傳送和接收資料的虛擬鏈路。
  • TCP協議負責收集資料包,並將它們按適當的次序傳送,接收端收到後再將它們正確地還原。
  • TCP協議使用重發機制: 當一個通訊實體傳送一個訊息給另一個通訊實體後,需收到另一個通訊實體的確認資訊,如果沒有收到另一個通訊實體的確認資訊,則會再從發剛才傳送的資訊。
  • 通過TCP協議的重發機制,TCP協議嚮應用程式提供了可靠的通訊連線,使它能夠自動適應網上的各種變化,即使在Internet暫時出現堵塞的情況下,TCP也能保證通訊的可靠性。

雖然IP和TCP這兩個協議功能不盡相同,也可以分開單獨使用,但它們是在同一個時期作為一個協議來設計的,並且在功能上也是互補的。只有兩者結合起來,才能保證Internet在複雜的環境下正常執行。凡是要連線到Internet的計算機,都必須同時安裝和使用這兩個協議,因此實際使用中常常把這兩個協議統稱為TCP/IP協議。

Java中Socket通訊相關的API介紹

一、ServerSocket

  • 在兩個通訊實體沒有建立虛擬鏈路之前,必須有一個通訊實體先做出“主動姿態”,主動接收來自其他通訊實體的連線請求。可以將此做出“主動姿態”的通訊實體看做是TCP伺服器端。
  • Java中能接收其他通訊實體連線請求的類是ServerSocket。ServerSocket物件用於監聽來自客戶端的Socket連線,如果沒有連線,ServerSocket物件將一直處於等待狀態。

public ServerSocket(int port):使用指定的埠port來建立ServerSocket。為了避免與其他應用程式的通用埠衝突,建議使用1024以上的埠。 public ServerSocket(int port, int backlog): 指定連線佇列中最大能允許多少個來自客戶端的Socket連線請求。沒有指定backlog或backlog小於1,則使用預設值(Java1.7的預設值是50)。 public ServerSocket(int port, int backlog, InetAddress bindAddr): 在機器存在多個IP地址的情況下,允許通過localAddr引數來指定將ServerSocket繫結到指定的IP地址。

public Socket accept(): 監聽來自客戶端的連線請求。如果接收到一個客戶端Socket的連線請求,該方法將返回一個與客戶端Socket對應的Socket;否則該方法將一直處於等待狀態,執行緒也被阻塞。當呼叫此accept方法返回一個Socket物件後,通訊的兩端之間就形成網路虛擬鏈路,於是就可以通過兩端的Socket物件產生的IO流,經過網路虛擬鏈路進行通訊了。

public void close(): 當ServerSocket使用完畢後,通過該close方法來關閉ServerSocket。呼叫close方法後,accept中阻塞的執行緒將丟擲SocketException異常:throw new SocketException("Socket is closed");。並且與客戶端建立的Socket連線也會被關閉。

通常情況下,伺服器不會只接受一個客戶端請求,而應該不斷地接收來自客戶端的所有請求,所以Java程式通常會通過迴圈(比如一個死迴圈)不斷地呼叫ServerSocket的accept()方法。

二、Socket

客戶端通過建立一個Socket物件,連線到伺服器。

public Socket(String host, int port) public Socket(InetAddress address, int port)

  • 使用本地主機預設的IP地址和系統動態分配的埠, 建立一個Socket,並使該Socket物件連線到指定遠端主機和遠端埠的伺服器程式(連線成功後會通過伺服器端ServerSocket的accept()方法,在伺服器端返回一個與此客戶端Socket對應的伺服器端Socket物件)。
  • 遠端主機的IP地址可以使用字串形式的host表示,也可以封裝成一個InetAddress物件傳遞進來。

public Socket(String host, int port, InetAddress localAddr, int localPort) public Socket(InetAddress address, int port, InetAddress localAddr, int localPort)

  • 使用指定的本地IP地址localAddress,和指定的本地埠localPort,建立一個Socket,並使該Socket物件連線到指定遠端主機和遠端埠的伺服器程式(連線成功後會通過伺服器端ServerSocket的accept()方法,在伺服器端返回一個與此客戶端Socket對應的伺服器端Socket物件)。
  • 遠端主機的IP地址可以使用字串形式的host表示,也可以封裝成一個InetAddress物件傳遞進來。

public Socket(): 建立一個未連線的Socket物件。如果想將其與伺服器端的Socket連線, 還需調connect方法。 public void connect(SocketAddress endpoint, int timeout): 連線到endpoint指定的遠端伺服器端的Socket程式。設定timeout指定連線超時時間,單位ms。timeou設定為0表示沒有限制超時時間。

  • 通過SocketAddress的子類InetSocketAddress來封裝遠端主機和遠端埠,相關構造方法是InetSocketAddress(String hostname, int port)InetSocketAddress(InetAddress addr, int port)

public synchronized void setSoTimeout(int timeout): 從Socket中讀取輸入流設定的超時時間,單位是ms。

public InputStream getInputStream(): 返回該Socket物件對應的輸入流,讓程式通過該輸入流從遠端Socket中取出資料。 public OutputStream getOutputStream(): 返回該Socket物件對應的輸出流,讓程式通過該輸出流向遠端Socket中寫入資料。

  • API只是返回輸入/輸出節點流的基類,所以不管底層的IO流到底是什麼節點流,程式都可以將其包裝成處理流,從而提供更多方便的處理。

public synchronized void close(): 關閉該Socket物件,

  • Socket中,當前操作IO流的阻塞執行緒將會報SocketException異常;
  • 呼叫此close方法後的Socket物件,無法再進行連線。若還需連線,則要另外建立一個新的Socket物件;
  • 呼叫此close方法,Socket中的InputStream和OutputStream都會被關閉。

public boolean isClosed(): 判斷此Socket物件是否調了close方法做了關閉處理。

  • 如果只是調shutdownInput和/或shutdownOutput關閉了輸入/輸出流,而沒有調close方法關閉Socket,isClosed仍然返回true。

public void shutdownInput(): 關閉該Socket物件的輸入流,程式還可以通過該Socket的輸出流輸出資料。 public void shutdownOutput(): 關閉該Socket物件的輸出流,程式還可以通過該Socket的輸入流讀取資料。 public boolean isInputShutdown(): 判斷Socket物件的輸入流是否關閉。 public boolean isOutputShutdown(): 判斷Socket物件的輸出流是否關閉。

  • 即使對一個Socket物件先後呼叫shutdownInput和shutdownOutput,該Socket物件仍然沒有被關閉,只不過此時的Socket物件既不能輸入資料,也不能輸出資料。
  • 當呼叫了Socket物件的shutdownInput或shutdownOutput關閉輸入流或輸出流後,該Socket物件無法再次開啟輸入流或輸出流。因此這種做法不適合保持持久通訊狀態的互動式應用。

使用Java提供的Socket通訊相關API實現多人聊天功能

//TODO (加入多執行緒、在通訊資料中加入協議字元區分資料資訊、相關原始碼) 未完待續…