วันอังคารที่ 24 ธันวาคม พ.ศ. 2556

การเขียนโปรแกรมเครือข่ายด้วย Socket ตอนที่ 6 : TCP Concurrent Server

จากโปรแกรมเซิร์ฟเวอร์ในตอนที่ 3 จัดเป็นเซิร์ฟเวอร์แบบ iterative นั่นคือให้บริการไคลเอนต์ได้ครั้งละหนึ่งตัว ถ้ามีมากกว่าหนึ่งตัวตัวที่เข้ามาทีหลังจะต้องเข้าคิวรอจนกว่าจะถึงคิวตัวเอง ซึ่งเซิร์ฟเวอร์แบบนี้ไม่เหมาะสมกับงานที่ไคลเอนต์และเซิร์ฟเวอร์ต้องติดต่อกันเป็นเวลานาน ลองนึกภาพว่าถ้า Gmail ให้บริการแบบนี้ดูนะครับว่ามันจะเป็นยังไง ดังนั้นงานแบบนี้จะต้องเขียนเซิร์ฟเวอร์ที่ทำงานแบบพร้อมกัน (Concurrent) ครับ

ซึ่งการเขียนก็ไม่ได้ยากอะไร แนวคิดที่ผ่านมาในตอนต่าง ๆ ยังใช้ได้หมด แต่สิ่งที่เราจะเพิ่มเข้ามาคือเราจะนำเธรด (Thread) มาใช้ครับ หลักการก็คือหลังจากที่เซิร์ฟเวอร์รับการติดต่อจากไคลเอนต์เข้ามาแล้วแทนที่จะไปให้บริการไคลเอนต์เองเหมือนที่ผ่านมา ก็จะสร้างเธรด ขึ้นมาให้บริการไคลเอนต์แต่ละตัว ไปลองดูโค้ดกันครับ
  1. //TCPConcurrentServer.java
  2. import java.io.*; 
  3. import java.net.*; 
  4. import java.util.*;
  5. public class TCPConcurrentServer { 
  6.    public static void main(String argv[])  { 
  7.       String clientSentence; 
  8.       String capitalizedSentence; 
  9.       ServerSocket welcomeSocket = null;
  10.       try {
  11.          welcomeSocket = new ServerSocket(6789);
  12.       }
  13.       catch (IOException e) {
  14.          System.out.println("Cannot create a welcome socket");
  15.          System.exit(1);
  16.       }
  17.       while(true) {
  18.          try {  
  19.             System.out.println("The server is waiting ");
  20.             Socket connectionSocket = welcomeSocket.accept(); 
  21.    EchoThread echoThread = new EchoThread(connectionSocket);
  22.             echoThread.start();
  23.          }
  24.          catch (IOException e) {
  25.             System.out.println("Cannot create this connection");
  26.          }
  27.       }
  28.    } 
  29. //EchoThread.java
  30. import java.io.*; 
  31. import java.net.*; 
  32. import java.util.*;
  33. public class EchoThread extends Thread {
  34.     private Socket connectionSocket;
  35.     public EchoThread(Socket connectionSocket) {
  36.         this.connectionSocket = connectionSocket;
  37.     }
  38.     public void run() {
  39.          Scanner inFromClient = null;
  40.          DataOutputStream outToClient = null;
  41.          try {
  42.             inFromClient = new Scanner(connectionSocket.getInputStream());
  43.    outToClient = 
  44.               new DataOutputStream(connectionSocket.getOutputStream()); 
  45.    String clientSentence = inFromClient.nextLine(); 
  46.          String capitalizedSentence = clientSentence.toUpperCase() + '\n'; 
  47.          outToClient.writeBytes(capitalizedSentence);         
  48.             
  49.    }
  50.         catch (IOException e) {
  51.             System.err.println("Closing Socket connection");
  52.         }
  53.         finally {
  54.             try {
  55.                if (inFromClient != null)
  56.                   inFromClient.close();
  57.                if (outToClient != null)
  58.                   outToClient.close();
  59.                if (connectionSocket != null)
  60.                   connectionSocket.close();
  61.                }
  62.             catch (IOException e) {
  63.                e.printStackTrace();
  64.             }
  65.         }
  66.     }
  67. }

สิ่งที่แตกต่างจากโปรแกรม iterative server ก็คือ คลาส EchoThread ในบรรทัดที่ 30-68 ซึ่งเป็นคลาสที่เขียนขึ้นเพื่อเป็นส่วนของการให้บริการไคลเอนต์ในการแปลงตัวอักษรตัวเล็กเป็นตัวใหญ่ จะเห็นว่างานบริการไคลเอนต์ที่เคยอยู่ในตัวโปรแกรม TCPServer จะถูกนำมาเขียนในคลาสนี้ บรรทัดที่ 21 และ 22 ในคลาส TCPConcurrent  จะสร้างออบเจกต์ของ EchoThread และสั่งให้เทรดเริ่มทำงาน ให้สังเกตว่ามีการส่งซ็อกเก็ตเชื่อมต่อที่สร้างขึ้นมาให้ออบเจกต์ของคลาส EchoThread ผ่านทางคอนสตรักเตอร์ หลังจากสร้างออบเจกต์ และสั่งให้เธรดเริ่มทำงานในการบริการไคลเอนต์แล้ว โปรแกรมเซิร์ฟเวอร์ก็สามารถกลับไปรับการติดต่อจากไคลเอนต์ตัวถัดไปได้ โดยตอนนี้การบริการไคลเอนต์จะเป็นหน้าที่ของเธรดที่ถูกสร้างขึ้น และถ้ามีการติดต่อเข้ามาก็ทำแบบเดียวกันคือสร้างเธรดอีกตัวหนึ่งไปให้บริการไคลเอนต์

ในส่วนของโปรแกรมไคลเอนต์ เราสามารถใช้โปรแกรมเดิมได้โดยไม่ต้องแก้ไข ในการรันโปรแกรมเพื่อทดสอบก็ทำแบบเดียวกับการรันโปรแกรมทดสอบที่อธิบายไปแล้วในตอนที่แล้วนะครับ ซึ่งถ้าทุกอย่างถูกต้องโปรแกรมเซิร์ฟเวอร์จะตอบสนองกับไคลเอนต์ทุกตัวที่ติดต่อเข้ามาโดยไม่ต้องรอการเรียง
ลำดับ

สำหรับใครที่ไม่อยากพิมพ์โค้ดเองสามารถดาวน์โหลดได้จาก github ครับ

สำหรับใครที่ยังไม่เข้าใจว่าจะรันโปรแกรมยังไงดูได้จากวีดีโอนี้ครับ



สุดท้ายสำหรับวันนี้ก็ขอสุขสันต์วันคริสต์มาสมายังทุกคนครับ...

1 ความคิดเห็น:

  1. All the legitimate on-line casinos defend your password and banking information by way 1xbet of SSL or TSL certification. These security measures ensure your information stays limited to you. The ideal approach to see if an internet casino is secure or not is carry out somewhat research|to do some analysis}, making sure it is licensed by a recognized authority. You should also to|must also} read buyer critiques to make an knowledgeable choice. These offshore websites must fill out an in depth utility, including full financial information about their house owners and managers.

    ตอบลบ