<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 15.3 服務多個客戶 `JabberServer`可以正常工作,但每次只能為一個客戶程序提供服務。在典型的服務器中,我們希望同時能處理多個客戶的請求。解決這個問題的關鍵就是多線程處理機制。而對于那些本身不支持多線程的語言,達到這個要求無疑是異常困難的。通過第14章的學習,大家已經知道Java已對多線程的處理進行了盡可能的簡化。由于Java的線程處理方式非常直接,所以讓服務器控制多名客戶并不是件難事。 最基本的方法是在服務器(程序)里創建單個`ServerSocket`,并調用`accept()`來等候一個新連接。一旦`accept()`返回,我們就取得結果獲得的`Socket`,并用它新建一個線程,令其只為那個特定的客戶服務。然后再調用`accept()`,等候下一次新的連接請求。 對于下面這段服務器代碼,大家可發現它與`JabberServer.java`例子非常相似,只是為一個特定的客戶提供服務的所有操作都已移入一個獨立的線程類中: ``` //: MultiJabberServer.java // A server that uses multithreading to handle // any number of clients. import java.io.*; import java.net.*; class ServeOneJabber extends Thread { private Socket socket; private BufferedReader in; private PrintWriter out; public ServeOneJabber(Socket s) throws IOException { socket = s; in = new BufferedReader( new InputStreamReader( socket.getInputStream())); // Enable auto-flush: out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())), true); // If any of the above calls throw an // exception, the caller is responsible for // closing the socket. Otherwise the thread // will close it. start(); // Calls run() } public void run() { try { while (true) { String str = in.readLine(); if (str.equals("END")) break; System.out.println("Echoing: " + str); out.println(str); } System.out.println("closing..."); } catch (IOException e) { } finally { try { socket.close(); } catch(IOException e) {} } } } public class MultiJabberServer { static final int PORT = 8080; public static void main(String[] args) throws IOException { ServerSocket s = new ServerSocket(PORT); System.out.println("Server Started"); try { while(true) { // Blocks until a connection occurs: Socket socket = s.accept(); try { new ServeOneJabber(socket); } catch(IOException e) { // If it fails, close the socket, // otherwise the thread will close it: socket.close(); } } } finally { s.close(); } } } ///:~ ``` 每次有新客戶請求建立一個連接時,`ServeOneJabber`線程都會取得由`accept()`在`main()`中生成的`Socket`對象。然后和往常一樣,它創建一個`BufferedReader`,并用`Socket`自動刷新`PrintWriter`對象。最后,它調用`Thread`的特殊方法`start()`,令其進行線程的初始化,然后調用`run()`。這里采取的操作與前例是一樣的:從套掃字讀入某些東西,然后把它原樣反饋回去,直到遇到一個特殊的`"END"`結束標志為止。 同樣地,套接字的清除必須進行謹慎的設計。就目前這種情況來說,套接字是在`ServeOneJabber`外部創建的,所以清除工作可以“共享”。若`ServeOneJabber`構造器失敗,那么只需向調用者“拋”出一個異常即可,然后由調用者負責線程的清除。但假如構造器成功,那么必須由`ServeOneJabber`對象負責線程的清除,這是在它的`run()`里進行的。 請注意`MultiJabberServer`有多么簡單。和以前一樣,我們創建一個`ServerSocket`,并調用`accept()`允許一個新連接的建立。但這一次,`accept()`的返回值(一個套接字)將傳遞給用于`ServeOneJabber`的構造器,由它創建一個新線程,并對那個連接進行控制。連接中斷后,線程便可簡單地消失。 如果`ServerSocket`創建失敗,則再一次通過`main()`拋出異常。如果成功,則位于外層的`try-finally`代碼塊可以擔保正確的清除。位于內層的`try-catch`塊只負責防范`ServeOneJabber`構造器的失敗;若構造器成功,則`ServeOneJabber`線程會將對應的套接字關掉。 為了證實服務器代碼確實能為多名客戶提供服務,下面這個程序將創建許多客戶(使用線程),并同相同的服務器建立連接。每個線程的“存在時間”都是有限的。一旦到期,就留出空間以便創建一個新線程。允許創建的線程的最大數量是由`final int maxthreads`決定的。大家會注意到這個值非常關鍵,因為假如把它設得很大,線程便有可能耗盡資源,并產生不可預知的程序錯誤。 ``` //: MultiJabberClient.java // Client that tests the MultiJabberServer // by starting up multiple clients. import java.net.*; import java.io.*; class JabberClientThread extends Thread { private Socket socket; private BufferedReader in; private PrintWriter out; private static int counter = 0; private int id = counter++; private static int threadcount = 0; public static int threadCount() { return threadcount; } public JabberClientThread(InetAddress addr) { System.out.println("Making client " + id); threadcount++; try { socket = new Socket(addr, MultiJabberServer.PORT); } catch(IOException e) { // If the creation of the socket fails, // nothing needs to be cleaned up. } try { in = new BufferedReader( new InputStreamReader( socket.getInputStream())); // Enable auto-flush: out = new PrintWriter( new BufferedWriter( new OutputStreamWriter( socket.getOutputStream())), true); start(); } catch(IOException e) { // The socket should be closed on any // failures other than the socket // constructor: try { socket.close(); } catch(IOException e2) {} } // Otherwise the socket will be closed by // the run() method of the thread. } public void run() { try { for(int i = 0; i < 25; i++) { out.println("Client " + id + ": " + i); String str = in.readLine(); System.out.println(str); } out.println("END"); } catch(IOException e) { } finally { // Always close it: try { socket.close(); } catch(IOException e) {} threadcount--; // Ending this thread } } } public class MultiJabberClient { static final int MAX_THREADS = 40; public static void main(String[] args) throws IOException, InterruptedException { InetAddress addr = InetAddress.getByName(null); while(true) { if(JabberClientThread.threadCount() < MAX_THREADS) new JabberClientThread(addr); Thread.currentThread().sleep(100); } } } ///:~ ``` `JabberClientThread`構造器獲取一個`InetAddress`,并用它打開一個套接字。大家可能已看出了這樣的一個套路:`Socket`肯定用于創建某種`Reader`以及/或者`Writer`(或者`InputStream`和/或`OutputStream`)對象,這是運用`Socket`的唯一方式(當然,我們可考慮編寫一、兩個類,令其自動完成這些操作,避免大量重復的代碼編寫工作)。同樣地,`start()`執行線程的初始化,并調用`run()`。在這里,消息發送給服務器,而來自服務器的信息則在屏幕上回顯出來。然而,線程的“存在時間”是有限的,最終都會結束。注意在套接字創建好以后,但在構造器完成之前,假若構造器失敗,套接字會被清除。否則,為套接字調用`close()`的責任便落到了`run()`方法的頭上。 `threadcount`跟蹤計算目前存在的`JabberClientThread`對象的數量。它將作為構造器的一部分自增,并在`run()`退出時自減(`run()`退出意味著線程中止)。在`MultiJabberClient.main()`中,大家可以看到線程的數量會得到檢查。若數量太多,則多余的暫時不創建。方法隨后進入“休眠”狀態。這樣一來,一旦部分線程最后被中止,多作的那些線程就可以創建了。大家可試驗一下逐漸增大`MAX_THREADS`,看看對于你使用的系統來說,建立多少線程(連接)才會使您的系統資源降低到危險程度。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看