Java進階學習:網路伺服器編程

來源:互聯網
上載者:User
編程|伺服器|網路

  Java的Socket API提供了一個很方便的對象介面進行網路編程。本文用一個簡單的TCP Echo Server做例子,示範了如何使用Java完成一個網路伺服器。

  用作例子的TCP Echo Server是按以下方式工作的:

  當一個用戶端通過TCP串連到伺服器後,用戶端可以通過這個串連發送資料到服務端,而服務端接收到資料後會把這些資料用同一個TCP串連發送回用戶端。服務端會一直保持這個串連直到用戶端關閉它為止。

  因為伺服器需要能同時處理多個用戶端,我們先選用一個常見的多線程服務模型:

  讓一個Thread負責監聽服務連接埠,當有新的串連建立的時候,這個監聽的Thread會為這個串連建立一個新的Thread來處理它。這樣,伺服器可以接受多個串連,並讓多個Thread來分別處理它們。

  以下是相應的服務端程式:


  public class EchoServer implements Runnable {

  public void run() {

  try {

  ServerSocket svr = new ServerSocket(7);

  while (true) {

  Socket sock = svr.accept();

  new Thread(new EchoSession(sock)).start();

  }

  } catch (IOException ex) {

  throw new ExceptionAdapter(ex);

  }

  }

  }

  這段代碼先建立了一個ServerSocket的對象並讓其監聽在TCP連接埠7上,然後在一個迴圈中用accept()方法接收新的串連,並建立處理這一串連的Thread。實際處理每個用戶端串連的邏輯包含在EchoSession這個類裡面。

  在以上代碼中使用了ExceptionAdapter這個類,它的作用是把一個checked Exception封裝成RuntimeException。詳細的說明可以參考避免在Java中使用Checked Exception 一文。

  以下是EchoSession的代碼:


  public class EchoSession implements Runnable {

  public EchoSession(Socket s) {

  _sock = s;

  }

  public void run() {


  try {

  try {

  InputStream input = _sock.getInputStream();

  OutputStream output = _sock.getOutputStream();

  byte [] buf = new byte [128];            

  while (true) {

  int count = input.read(buf);

  if (count == -1)

  break;

  output.write(buf, 0 , count);

  }

  } finally {

  _sock.close();

  }

  } catch (IOException ex) {

  throw new ExceptionAdapter(ex);   

  }

  }

  protected Socket _sock = null;

  }

  EchoSession接受一個Socket對象作為構造參數,在其run()方法中,它不停的從這個Socket對象的InputStream裡面讀資料並寫回到該Socket的OutputStream中去,直到這個串連被用戶端關閉為止(InputStream的read方法返回-1)。

  EchoSession需要一個線程來執行,這容易讓人聯想到用Thread來作為EchoSession的父類。不過,這樣做不夠靈活,開銷也比較大。而選擇讓EchoSession實現Runnable介面就靈活得多。在接下來的使用Thread Pool的Echo Server中可以看到這一點。

  以上已經是一個完整的TCP Echo Server,不過隨著客戶不停的串連和斷開,這個伺服器會不停的產生和消除線程,而這兩個都是比較‘昂貴’的操作。為了避免這種消耗,可以考慮採用Thread Pool的機制。

  使用在一個簡單的Thread緩衝池的實現一文中Thread Pool的實現,可以對EchoServer作如下修改(EchoSession無需做修改):


  public class EchoServer implements Runnable {

  public void run() {

  try {

  ServerSocket svr = new ServerSocket(7);



  // 初始化Thread Pool

  SyncQueue queue = new SyncQueue(10);

  for (int i = 0; i < 10; i ++) {

  new Thread(new Worker(queue)).start();

  }

  while (true) {

  Socket sock = svr.accept();

  // 把任務放入Thread Pool

  queue.put(new EchoSession(sock));

  }

  } catch (IOException ex) {

  throw new ExceptionAdapter(ex);

  }

  }

  }

  這裡可以看出讓EchoSession實現Runnable介面的靈活性,無需修改它就可以在Thread Pool裡使用。

  在這個例子裡使用的Thread Pool比較簡單,沒有動態調整Thread數量的功能,所以這個Echo Server最多隻能同時服務10個用戶端。然而通過重載SyncQueue,我們可以很方便地加入這個功能以突破這個限制。

  在對網路伺服器的效能以及並發度要求很高的時候,讓每個用戶端由一個專門的Thread來處理有可能不能滿足我們的要求(想象一下同時有數千個用戶端的情況)。這時可以考慮使用Java的NIO API來構建伺服器架構,因為NIO中IO操作都是非阻塞的,我們只需要很少的Thread就可以充分地利用CPU來處理多個用戶端的請求。關於NIO的話題,在這篇文章就不再贅述,希望以後能有機會討論。 :)



聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.