MQTT (MQ TELEMETRY TRANSPORT)MQTT เป็นโพรโทคอลสื่อสารชั้นแอปพลิเคชั่นที่รันบน TCP/IP ถูกพัฒนาขึ้นในปี 1999 โดย IBM และ Eurotech สำหรับการมอนิเตอร์สถานะท่อส่งน้ำมันส่วนที่วางผ่านเขตทะเลทราย ด้วยการออกแบบให้เป็นการรับส่งข้อความที่มีน้ำหนักเบามากและเป็นโพรโทคอลเปิด ทำให้ในปัจจุบัน MQTT ถูกนำมาใช้แพร่หลายในการสื่อสารแบบ M2M หรือ IoT เพราะเหมาะสมกับอุปกรณ์ปลายทางที่มีขนาดเล็ก/พลังงานจำกัด หรือในการสื่อสารระยะไกลที่ต้องการการใช้งานแบนด์วิดธ์อย่างมีประสิทธิภาพ โมเดลการสื่อสารของโพรโทคอลแสดงดังรูปที่ 1.3 ประกอบด้วย 2 ส่วนคือไคลเอนต์ และโบรกเกอร์ รูปที่ 1.3 โมเดลการสื่อสารของโพรโทคอล MQTT โบรกเกอร์ เป็นจุดศูนย์กลางในการรับส่งข้อความระหว่างไคลเอนต์ วิธีการกำหนดเส้นทาง (Routing) กระทำผ่าน Topic โดยไคลเอนต์ Subscribe ใน Topic ที่ตนต้องการ จากนั้นโบรกเกอร์จะส่งข้อความทั้งหมดที่ถูก Publish ใน Topic นั้นๆ ไปให้ ดังนั้นไคลเอนต์จึงสื่อสารกันได้โดยไม่จำเป็นต้องรู้จักกัน ช่วยลดความเกี่ยวพันระหว่างผู้สร้างข้อมูลและผู้ใช้ข้อมูล ส่งผลให้การขยายตัวของเครือข่ายทำได้ง่าย นอกจากนี้หน้าที่ที่สำคัญอีกประการของโบรกเกอร์คือการรักษาความปลอดภัยของไคลเอนต์ (Authorization, Authentication) ซึ่งในส่วนนี้สามารถขยายเพิ่มเติม หรือนำไปเชื่อมกับกลไกความปลอดภัยของระบบหลังบ้านที่มีอยู่แล้วได้ ช่วยให้นำโบรกเกอร์เข้าไปใช้งานเป็นส่วนหนึ่งของระบบอื่นๆ ได้ ส่วน Authorization ของ NETPIE ซึ่งจะได้กล่าวถึงต่อไปในหัวข้อที่ 1.4 ก็ถือเป็นตัวอย่างหนึ่งของการขยายเพิ่มเติมการรักษาความปลอดภัยของโบรกเกอร์ใน MQTT ปัจจุบันมีโบรกเกอร์ MQTT ที่เปิดให้ดาวน์โหลดไปใช้หรือดัดแปลงอยู่หลายรายได้แก่ Mosquitto, RabbitMQ, Erlang, VerneMQ ฯลฯ ไคลเอนต์ จะเป็นได้ทั้ง Publisher หรือ Subscriber หรือ Publisher/Subscriber พร้อมๆ กัน และจะเป็นอุปกรณ์ใดๆ ก็ได้ที่สามารถรัน MQTT Client Library บน TCP/IP Stack การที่ MQTT ใช้โมเดล Publish/Subscribe ตรรกะส่วนใหญ่จึงไปตกอยู่ในฝั่งโบรกเกอร์ ทำให้ Library มีขนาดเล็ก ติดตั้งได้ง่าย ใช้งานได้กับอุปกรณ์ที่มีทรัพยากรจำกัด ไคลเอนต์จำเป็นต้องเปิดการเชื่อมต่อ TCP ไว้ตลอดเพื่อที่โบรกเกอร์จะสามารถผลักข้อความไปให้ได้ หากการเชื่อมต่อถูกตัดขาด โบรกเกอร์จะเก็บข้อความทั้งหมดที่เข้ามาไว้จนกว่าไคลเอนต์จะกลับมาออนไลน์อีกครั้ง เมื่อเปรียบเทียบ MQTT กับ HTTP (REST) ที่มีสถาปัตยกรรมแบบ Request/Response จะพบว่า MQTT มีความได้เปรียบที่โบรกเกอร์สามารถผลัก (Push) ข้อความไปยังไคลเอนต์ได้ตามเหตุการณ์ (Event-driven) ในขณะที่เมื่อใช้ HTTP ฝั่งไคลเอนต์ต้องคอยโพลข้อมูลเป็นระยะๆ และต้องตั้งค่าคาบเวลาการโพลไว้ก่อนล่วงหน้า โดยแต่ละครั้งต้องมีการสร้างการเชื่อมต่อขึ้นใหม่และอาจจะไม่มีข้อมูลใหม่ใดๆ ให้อัพเดท ดังนั้นหากต้องการให้ระบบทำงานแบบ Real Time หรือใกล้เคียง ย่อมหมายถึงต้องตั้งคาบเวลาการโพลให้สั้น และความสิ้นเปลืองของการใช้ช่องสัญญาณที่ไม่จำเป็นที่ตามมา นี่จึงเป็นอีกเหตุผลสำคัญที่ทำให้ MQTT ได้รับความนิยมเหนือ REST สำหรับการใช้งานแบบ M2M นอกเหนือจากการมีน้ำหนักเบา MQTT TopicsMQTT Topic เป็น UTF-8 String ในลักษณะเดียวกับ File Path คือสามารถจัดเป็นลำดับชั้นได้ด้วยการขั้นด้วย “/” ตัวอย่างเช่น myhome/floor-one/room-c/temperature ไคลเอนต์สามารถเลือก Publish หรือ Subscribe เฉพาะ Topic หรือ Subscribe หลาย Topic พร้อมๆ กันโดยใช้ Single-Level Wildcard (+) เช่น myhome/floor-one/+/temperature หมายถึงการขอเขียนหรือรับข้อความ temperature จากทุกๆ ห้องของ myhome/floor-one หรือ Multi-Level Wildcard (#) เช่น myhome/floor-one/# หมายถึงการขอเขียนหรือรับข้อความทั้งหมดที่มี Topic ขึ้นต้นด้วย myhome/floor-one เป็นต้น เราสามารถกำหนด Topic อย่างไรก็ได้ โดยมีข้อยกเว้นการขึ้นต้น Topic ด้วยเครื่องหมาย “$” ซึ่งจะจำกัดไว้สำหรับการเก็บสถิติภายในของตัวโบรกเกอร์เท่านั้น ดังนั้นไคลเอนต์จะไม่สามารถ Publish หรือ Subscribe ไปยัง Topic เหล่านี้ได้ โดยทั่วไป Topic เหล่านี้จะขึ้นต้นด้วย $SYS
MQTT Connectionsแพ็กเกตควบคุม (Control Packets) ทั้งหมดที่ใช้ในการสื่อสารระหว่างโบรกเกอร์กับไคลเอนต์ใน MQTT มีทั้งสิ้น 14 ชนิด แสดงไว้ดังตารางที่ 1.1
การเชื่อมต่อ MQTT จะเริ่มต้นจากฝั่งไคลเอนต์ส่งแพ็กเกตควบคุม CONNECT ไปยังโบรกเกอร์ โบรกเกอร์จะตอบรับด้วยแพ็กเกตควบคุม CONNACK วิธีนี้ช่วยแก้ปัญหาไคลเอนต์ที่ติดตั้งอยู่หลังเราท์เตอร์หรือไม่มีเลขไอพีสาธารณะ เพราะโบรกเกอร์มีเลขไอพีสาธารณะและจะรักษาการเชื่อมต่อสองทางไว้ตลอดหลังจากได้รับแพ็กเกตควบคุม CONNECT หากโบรกเกอร์พบว่าแพ็กเกต CONNECT ที่ได้รับไม่ถูกต้อง หรือไคลเอนต์ใช้เวลานานเกินไปนับตั้งแต่เปิดซ็อกเก็ตจนกระทั่งเริ่มส่งแพ็กเกต โบรกเกอร์จะปิดการเชื่อมต่อเพื่อป้องกันไคลเอนต์ไม่ประสงค์ดีที่ต้องการถ่วงการทำงานของโบรกเกอร์ ไคลเอนต์จะเป็นผู้ระบุค่าการเชื่อมต่อในแพ็กเกตควบคุม CONNECT ค่าเหล่านี้ ได้แก่
รูปที่ 1.4 ผังการรับส่งข้อความสั่งเสียสุดท้าย (Last Will Message) 1 ไคลเอนต์ Publish ข้อความ โดยบรรจุลงในส่วน Payload ของแพ็กเกตควบคุม PUBLISH ซึ่งจะต้องระบุ Packet ID, ชื่อ Topic, ระดับของ QoS, Duplicate Flag และ Retain Flag โบรกเกอร์จะตอบกลับด้วยแพ็กเกต PUBACK หรือ PUBREC ขึ้นอยู่กับระดับ QoS ที่ระบุในแพ็กเกต PUBLISH ในทางกลับกันเมื่อต้องการรับข้อมูล ไคลเอนต์ส่งแพ็กเกตควบคุม SUBSCRIBE ไปยังโบรกเกอร์ โดยระบุรายชื่อ Topic ที่ต้องการ ซึ่งอาจมีได้มากกว่าหนึ่ง และสามารถเลือกตั้งค่าระดับ QoS ที่แตกต่างกันสำหรับแต่ละ Topic และโบรกเกอร์จะตอบด้วยแพ็กเกต SUBACK โดยยืนยันค่าระดับ QoS ของแต่ละ Topic ที่ไคลเอนต์ขอ Subscribe กลับมาอีกครั้ง หาก Topic ใดที่ไม่อนุญาตหรือไม่ปรากฏบนโบรกเกอร์ โบรกเกอร์จะตอบกลับด้วยค่า 128 แทนที่ค่าระดับ QoS เมื่อไคลเอนต์ต้องการยกเลิกการรับข้อมูล ทำได้โดยการส่งแพ็กเกตควบคุม UNSCRIBE ไปยังโบรกเกอร์ โดยระบุรายชื่อ Topic ที่ต้องการบอกเลิกในคราวเดียวกันได้มากกว่าหนึ่ง โบรกเกอร์จะยืนยันการยกเลิกด้วยแพ็กเกต UNSUBACK เมื่อไคลเอนต์ต้องการเลิกการเชื่อมต่อ ทำได้โดยการส่งแพ็กเกตควบคุม DISCONNECT ไปยังโบรกเกอร์ หากไคลเอนต์ CONNECT โดยตั้งค่า Clean Session เป็น True โบรกเกอร์จะยกเลิก Subscription ทั้งหมดของไคลเอนต์ให้เองโดยอัตโนมัติ ในทางกลับกันหาก Clean Session เป็น False โบรกเกอร์จะยังคงเก็บค่าต่างๆ ของเซสชั่นไว้ เมื่อไคลเอนต์เชื่อมต่อเข้ามาใหม่ด้วย Client ID เดิม จึงไม่จำเป็นต้องเริ่ม Subscribe ใหม่อีกครั้ง MQTT Quality of Service (QoS)ไคลเอนต์จะเป็นผู้กำหนดระดับของบริการส่งและรับข้อความหรือ QoS ที่ตนต้องการในแต่ละ Topic ในแพ็กเกต PUBLISH หรือ SUBSCRIBE และโบรกเกอร์จะตอบสนองด้วย QoS ระดับเดียวกันสำหรับ Topic นั้นๆ QoS ใน MQTT แบ่งได้เป็น 3 ระดับ คือ
รูปที่ 1.5 ผังการสื่อสารเพื่อ Publish ข้อความด้วย QoS 01 รูปที่ 1.6 ผังการสื่อสารเพื่อ Publish ข้อความด้วย QoS 11 รูปที่ 1.7 ผังการสื่อสารเพื่อ Publish ข้อความด้วย QoS1 Retained Messages เมื่อไคลเอนต์ Publish ข้อความแบบ Retained Message โดยการตั้ง Retain Flag เป็น True จะทำให้โบรกเกอร์เก็บข้อความนั้นไว้ใน Topic ที่ระบุอย่างถาวร จนกว่าจะมี Retained Message อื่นที่ถูก Publish ภายหลังมาเก็บแทนที่ โดยโบรกเกอร์จะเก็บ Retained Message ไว้ให้เพียง Topic ละหนึ่งข้อความ ดังนั้นทุกครั้งที่มีไคลเอนต์ Subscribe เข้ามาใหม่ ก็จะได้รับ Retained Message ทันที ไม่ต้องรอจนกว่าจะมี Publication ใหม่เกิดขึ้น จึงมองได้ว่า Retained Message คือข้อมูลสุดท้ายที่ Subscriber ทุกรายควรต้องทราบ ดังนั้น Retained Message จึงเป็นประโยชน์อย่างยิ่งกับแอปพลิเคชั่นที่เกี่ยวข้องกับการอัพเดทสถานะ หากไคลเอนต์ต้องการลบ Retained Message ใน Topic ใดๆ ก็สามารถทำได้ไม่ยาก ด้วยการส่งแพ็กเกต PUBLISH ที่มีไม่มี Payload และตั้ง Retain Flag เป็น True ไปยัง Topic นั้นๆ หรือหากมีข้อมูลจะอัพเดท ก็ไม่มีความจำเป็นต้องลบ Retained Message เก่าออกก่อน แต่สามารถส่ง Retained Message เข้าไปเขียนทับได้เลย แบบฝึกหัด: Local MQTT Chat บน Raspberry Pi 1.ติดตั้งโบรกเกอร์ Mosquitto ลงบน Raspberry Pi โดยพิมพ์ชุดคำสั่งข้างล่าง และแทนที่ xxxx ด้วยชื่อรุ่นระบบปฏิบัติการเช่น wheezy หรือ jessie
2.ติดตั้งไคลเอนต์
3.ทดลองแชทโดยเปิดหน้าต่าง สร้างหัวข้อ “chat/test1” ลงบนโบรกเกอร์บนเครื่องและ Subscribe โดยพิมพ์
4.เปิดหน้าต่างใหม่โดยยังไม่ปิดหน้าต่างแรก พิมพ์คำสั่งข้างล่างเพื่อ Publish ข้อความ “hello” ไปยังหัวข้อ “chat/test1”
ในหน้าต่างแรกที่ได้ Subscribe เอาไว้ จะปรากฏข้อความ hello 5.สังเกตผลแตกต่างของการตั้งระดับบริการรับส่งข้อมูล (QoS) ที่แตกต่างกัน พิมพ์คำสั่งข้างล่างในหน้าต่างแรกเพื่อ Subscribe ในหัวข้อ “chat/test2” ด้วย QoS 1
6.ในหน้าต่างที่สอง พิมพ์คำสั่งข้างล่างเพื่อ Publish ข้อความ “You might get this message.” และ “You will get this message.” ด้วย QoS 0 และ QoS 1 ตามลำดับ
7.สังเกตผลลัพธ์ในหน้าต่างแรก 8.หยุดการทำงานของหน้าต่างแรกชั่วคราวโดย ctrl-c 9.ทำซ้ำข้อ 6 10.ทำซ้ำข้อ 5 และสังเกตผลลัพธ์ |