สำหรับแนวคิดของการอ่านและเขียนข้อมูลกับซ็อกเก็ตนั้นจะใช้แนวคิดของสตรีม (Stream) ซึ่งก็คือแนวคิดที่จาวา (Java) ใช้ในการรับส่งข้อมูลระหว่างโปรแกรมที่เขียนด้วยภาษาจาวา กับอุปกรณ์รอบข้าง หรือกับไฟล์ ตัวอย่างเช่น เวลาจะพิมพ์ข้อมูลออกมาทางจอภาพเราจะใช้คำสั่ง System.out.println("string"); ประโยคนี้ out คือสตรีมผลลัพธ์ (output stream) ซึ่งอ้างถึงตัวแสดงผลลัพธ์มาตรฐาน ซึ่งก็คือจอภาพนั่นเอง การเขียนโปรแกรมซ็อกเก็ตของภาษาจาวา (Java) ก็จะใช้แนวคิดนี้ เพียงแต่สตรีมที่เราสร้างขึ้น จะเชื่อมโยงกับซ็อกเก็ตแทนที่จะเป็นอุปกรณ์หรือไฟล์
คลาสในภาษาจาวาที่ใช้สร้างเซิฟร์เวอร์ซ็อกเก็ตก็คือ ServerSocket ส่วนคลาสที่ใช้ในการสร้างซ็อกเก็ตเชื่อมต่อก็คือ ConnectionSocket นั่นเอง เอาล่ะครับเพื่อให้เข้าใจการทำงานมาดูตัวอย่างกันดีกว่า สำหรับโปรแกรมเซิร์ฟเวอร์ที่จะเขียนขึ้นมาก็คือเซิร์ฟเวอร์ที่ใช้ในการแปลงข้อความภาษาอังกฤษที่รับเข้ามาจากไคลเอนต์ ให้เป็นตัวอักษรตัวใหญ่ทั้งหมดแล้วส่งกลับไปให้ไคลเอนต์ สำหรับโค้คภาษาจาวา ของโปรแกรมแสดงได้ดังนี้ครับ
- import java.io.*;
- import java.net.*;
- import java.util.*;
- class TCPServer {
- public static void main(String argv[]) {
- String clientSentence;
- String capitalizedSentence;
- ServerSocket welcomeSocket = null;
- Socket connectionSocket = null;
- Scanner inFromClient = null;
- DataOutputStream outToClient = null;
- try {
- welcomeSocket = new ServerSocket(6789);
- }
- catch (IOException e) {
- System.out.println("Cannot create a welcome socket");
- System.exit(1);
- }
- while(true) {
- try {
- System.out.println("The server is waiting ");
- connectionSocket = welcomeSocket.accept();
- inFromClient = new Scanner(connectionSocket.getInputStream());
- outToClient =
- new DataOutputStream(connectionSocket.getOutputStream());
- clientSentence = inFromClient.nextLine();
- capitalizedSentence = clientSentence.toUpperCase() + '\n';
- outToClient.writeBytes(capitalizedSentence);
- }
- catch (IOException e) {
- System.out.println("Error cannot create this connection");
- }
- finally {
- try {
- if (inFromClient != null)
- inFromClient.close();
- if (outToClient != null)
- outToClient.close();
- if (connectionSocket != null)
- connectionSocket.close();
- }
- catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- }
สำหรับโปรแกรมนี้ก็มีส่วนที่จะอธิบายดังนี้ครับ บรรทัดที่ 13 เป็นการสร้างเซิร์ฟเวอร์ซ็อกเก็ตโดยใช้หมายเลขพอร์ต 6789 ในการรอรับการติดต่อกับไคลเอนต์ บรรทัดที่ 22 จะเห็นว่ามีการเรียกใช้เมท็อด accept() เมท็อดนี้จะมีผลทำให้โปรแกรมเซิร์ฟเวอร์หยุดรอรับการติดต่อจากไคลเอนต์ เมื่อไคลเอนต์ติดต่อเข้ามาก็จะสร้างซ็อกเก็ตเชื่อมต่อเพื่อใช้ในการแลกเปลี่ยนข้อมูล บรรทัดที่ 23 สร้างสตรีมข้อมูลเข้า (input stream) เพื่ออ่านข้อมูลจากซ็อกเก็ต บรรทัดที่ 24-25 สร้างสตรีมผลลัพธ์ (output stream) เพื่อเขียนข้อมูลลงซ็อกเก็ต บรรทัดที่ 26 หยุดเพื่อรออ่านข้อมูลที่ไคลเอนต์จะส่งผ่านซ็อกเก็ตมา บรรทัดที่ 27 แปลงสตริงที่รับมาให้เป็นตัวอักษรตัวใหญ่ และบรรทัดที่ 28 เขียนข้อมูลผ่านซ็อกเก็ตกลับไปให้ไคลเอนต์ ใน finally clause จะปิด stream ที่สร้างขึ้นมาทั้งหมด และซ็อกเก็ตเชื่อมต่อตัวนี้ เนื่องจากในตัวอย่างนี้เซิฟร์เวอร์จะแปลงสตริงที่ไคลเอนต์ส่งเข้ามา ส่งสตริงที่แปลงกลับไป และตัดการเชื่อมต่อกับไคลเอนต์ทันที และข้อสังเกตที่น่าสนใจก็คือจะเห็นว่าเราให้โปรแกรมนี้ทำงานอยู่ในลูปไม่รู้จบ ซึ่งเป็นธรรมชาติของโปรแกรมเซิร์ฟเวอร์ที่จะทำงานไปเรื่อย ๆ
โปรแกรมเซิร์ฟเวอร์ตัวนี้ให้บริการไคลเอนต์ครั้งละหนึ่งตัว เมื่อให้บริการไคลเอนต์ตัวหนึ่งเสร็จจึงจะไปให้บริการไคลเอนต์ตัวอื่นที่ติดต่อเข้ามาได้ ลักษณะของโปรแกรมเซิร์ฟเวอร์แบบนี้เราจะเรียกว่า iterative server ซึ่งก็คือเซิร์ฟเวอร์ที่ให้บริการไคลเอนต์ได้ครั้งละหนึ่งตัว ถ้ามีไคลเอนต์ตัวอื่นติดต่อเข้ามาขณะที่เซิร์ฟเวอร์กำลังให้บริการไคลเอนต์ตัวอื่นอยู่ ไคลเอนต์ที่ติดต่อเข้ามาก็จะถูกเข้าคิวไว้ เมื่อเซิร์ฟเวอร์ให้บริการไคลเอนต์ตัวนี้เสร็จก็จะกลับไปให้บริการไคลเอนต์ในคิว สำหรับเซิร์เวอร์ที่ให้บริการไคลเอนต์ได้ทีละหลายตัวพร้อมกันที่เรียกว่า concurrent server นั้น ทำได้โดยใช้เธรด (thread) ซึ่งจะกล่าวถึงในตอนต่อ ๆ ไป
สำหรับโปรแกรมต้นฉบับ (source code) สามารถโหลดได้จากลิงก์นี้ครับ ซึ่งจะได้โปรแกรมทั้งฝั่งเซิร์ฟเวอร์และไคลเอนต์เลย แต่บล็อกเกี่ยวกับไคลเอนต์โปรแกรมจะอยู่ในตอนหน้านะครับ
เมื่อรันโปรแกรมนี้ โปรแกรมจะแสดงสถานะว่าโปรแกรมเซิร์ฟเวอร์กำลังทำงานอยู่ ซึ่งในโปรแกรมเซิร์ฟเวอร์จริง ๆ ไม่จำเป็นต้องมีการทำงานส่วนนี้นะครับ
ขอบคุณครับ
ตอบลบมีประโยชน์มากๆเลย ขอบคุณนะครับ
ตอบลบ