فصل سوم: اطمینان تحویل پیام و مدیریت قطع ارتباط
مقدمه
در فصل اول با جایگاه پروتکل MQTT در اتوماسیون صنعتی و مدل انتشار و اشتراک آشنا شدیم. در فصل دوم نیز آموختیم چگونه تاپیکها، قالب پیامها و متغیرهای صنعتی را بهصورت منظم طراحی کنیم.
اکنون به یکی از مهمترین مسائل ارتباطات صنعتی میرسیم: اگر پیام به مقصد نرسد، ارتباط قطع شود یا یک فرمان دوبار دریافت شود، چه اتفاقی خواهد افتاد؟
فرض کنید در یک کارخانه، کنترلری دمای تابلوی برق را اندازهگیری میکند و مقدار آن را از طریق MQTT به نمایشگر اتاق کنترل میفرستد. در شرایط عادی، مقدار دما روی نمایشگر بهروزرسانی میشود و اپراتور میتواند وضعیت تابلو را مشاهده کند.
اما حالتی را در نظر بگیرید که ارتباط کنترلر با بروکر قطع شود. آیا نمایشگر باید آخرین مقدار دما را همچنان نشان دهد؟ چگونه میتواند بفهمد این مقدار قدیمی است؟ اگر کنترلر دوباره متصل شود، آیا پیامهایی که در زمان قطعی تولید شدهاند به مقصد خواهند رسید؟
مسئله هنگام ارسال فرمان حساستر میشود.
فرض کنید اپراتور از طریق اچامآی درخواست روشنشدن یک موتور را ارسال میکند. ممکن است بروکر پیام را دریافت کرده باشد، اما کنترلر هنوز آن را پردازش نکرده باشد. همچنین ممکن است کنترلر فرمان را دریافت و اجرا کرده باشد، ولی پاسخ آن به نمایشگر نرسیده باشد.
در چنین شرایطی، ارسال دوباره فرمان بدون بررسی وضعیت قبلی میتواند مشکل ایجاد کند.
پروتکل MQTT امکاناتی برای مدیریت بخشی از این شرایط فراهم میکند، اما تمام مسئولیت اطمینان از عملکرد صحیح تجهیزات صنعتی را بر عهده نمیگیرد.
در این فصل، با استفاده از مثالهای واقعی اتوماسیون صنعتی، روشهای تحویل پیام، نگهداری اطلاعات، تشخیص قطع ارتباط و بازیابی ارتباط را بررسی خواهیم کرد.
هدف آن است که بتوانیم میان چهار موضوع تفاوت قائل شویم:
• اطمینان از انتقال پیام در سطح پروتکل
• تشخیص دریافت و پردازش پیام توسط برنامه
• تشخیص انجام واقعی یک فرمان
• حفظ اعتبار دادهها هنگام قطع و وصل ارتباط
در پایان فصل، یک ساختار فرمان قابلپیگیری طراحی خواهیم کرد که علاوه بر ارسال درخواست، نتیجه بررسی و بازخورد واقعی دستگاه را نیز مشخص میکند.
۱. تفاوت ارسال پیام، دریافت پیام و اجرای فرمان
یکی از مهمترین اصول در طراحی ارتباط صنعتی این است که ارسال موفق پیام الزاماً به معنی اجرای موفق فرمان نیست.
برای روشنشدن این موضوع، مسیر یک فرمان موتور را بررسی میکنیم.
فرض کنید اپراتور روی اچامآی دکمه روشنشدن موتور را فشار میدهد.
نمایشگر پیامی را با موضوع زیر منتشر میکند:
factory/line1/motor01/cmd/run
محتوا:
{"value":true}
این پیام ابتدا از نمایشگر به بروکر ارسال میشود. بروکر براساس اشتراکهای ثبتشده، آن را برای کنترلر موتور ارسال میکند.
پس از آن، برنامه کنترلر باید محتوای پیام را تفسیر کرده و درباره اجرای درخواست تصمیم بگیرد.
بنابراین چند مرحله مستقل وجود دارد.
مرحله اول: ارسال درخواست به بروکر
در این مرحله، کلاینت نمایشگر پیام را برای بروکر ارسال میکند.
برحسب سطح کیفیت سرویس و پیادهسازی کتابخانه، نرمافزار ممکن است از پذیرفتهشدن پیام در مسیر ارتباطی خود اطمینان پیدا کند.
اما این وضعیت به معنی آن نیست که کنترلر موتور پیام را دریافت کرده است.
مرحله دوم: تحویل پیام به کنترلر
بروکر پیام را برای کنترلری ارسال میکند که اشتراک مناسب دارد.
در این مرحله نیز دریافت پیام توسط کلاینت کنترلر، الزاماً به معنی پردازش آن توسط منطق برنامه نیست.
مرحله سوم: بررسی فرمان
برنامه کنترلر باید شرایط لازم را بررسی کند.
برای مثال، اگر خطای اضافهبار موتور فعال باشد، درخواست روشنشدن نباید اجرا شود.
کنترلر میتواند نتیجه بررسی را در موضوع پاسخ منتشر کند:
factory/line1/motor01/response/run
نمونه پاسخ:
{
"accepted": false,
"reason": "overload"
}
مرحله چهارم: انجام عمل و مشاهده نتیجه
اگر فرمان مجاز باشد، کنترلر خروجی مناسب را فعال میکند.
اما حتی فعالشدن خروجی نیز همیشه به معنی روشنشدن واقعی موتور نیست.
ممکن است کنتاکتور عمل نکند، درایو خطا داشته باشد یا موتور به دلیل مشکل دیگری راهاندازی نشود.
بنابراین وضعیت واقعی باید از بازخورد مناسب مشخص شود.
factory/line1/motor01/status/running
{"running":true}
در پروژهای که بازخورد واقعی وجود ندارد، نمیتوان تنها از روی فرمان صادرشده با قطعیت اعلام کرد موتور روشن است.
نتیجه
چهار وضعیت زیر باید از یکدیگر تفکیک شوند:
| وضعیت | معنی |
| پیام ارسال شد | فرستنده عملیات انتشار را آغاز یا تکمیل کرده است. |
| پیام تحویل شد | پیام طبق قواعد پروتکل به کلاینت مقصد رسیده است. |
| فرمان پذیرفته شد | برنامه کنترلر درخواست را معتبر و مجاز تشخیص داده است. |
| عمل انجام شد | نتیجه واقعی با بازخورد مناسب تأیید شده است. |
این تفکیک پایه طراحی فرمانهای صنعتی قابلاعتماد است.
۲. شناخت سطح کیفیت سرویس
پروتکل MQTT برای انتقال پیام، سه سطح کیفیت سرویس تعریف میکند.
نام این ویژگی:
Quality of Service
QoS
سطح کیفیت سرویس مشخص میکند فرستنده و دریافتکننده در هر مرحله ارتباط MQTT از چه سازوکاری برای تحویل پیام استفاده کنند.
سه سطح عبارتاند از:
QoS 0
QoS 1
QoS 2
این سطحها از نظر تعداد مراحل تبادل و نوع تضمین تحویل متفاوتاند.
نکته مهم آن است که کیفیت سرویس مربوط به تحویل پیام در پروتکل MQTT است، نه اجرای منطق صنعتی موجود در محتوای پیام.
برای مثال، حتی استفاده از بالاترین سطح کیفیت سرویس نمیتواند تضمین کند یک موتور واقعاً روشن شده است.
همچنین کیفیت سرویس تعیین نمیکند که داده سنسور صحیح است یا خیر.
انتخاب سطح مناسب باید با توجه به نوع داده، اهمیت پیام، تعداد تجهیزات، توان پردازشی و شرایط شبکه انجام شود.
۳. نحوه عملکرد سطح صفر کیفیت سرویس
در سطح صفر، پیام با یک بسته انتشار ارسال میشود و برای آن تأیید دریافت مخصوص کیفیت سرویس در نظر گرفته نشده است.
این سطح با عبارت زیر شناخته میشود:
At most once
یعنی تحویل پیام حداکثر یکبار انجام میشود.
روش عملکرد
فرض کنید کنترلر دمای تابلو را اندازهگیری میکند.
موضوع:
factory/line1/panel01/telemetry/temperature
محتوا:
{"value":38.5}
کنترلر پیام را منتشر میکند و پروتکل در این سطح منتظر دریافت تأیید تحویل نمیماند.
اگر ارتباط در زمان انتقال قطع شود، امکان ازدسترفتن پیام وجود دارد.
کاربرد صنعتی
فرض کنید کنترلر هر پنج ثانیه دمای جدیدی منتشر میکند.
اگر یک پیام از دست برود، پیام بعدی میتواند مقدار تازهتری در اختیار نمایشگر قرار دهد.
در چنین کاربردی، دریافت تمام نمونهها ممکن است ضروری نباشد.
اما اگر هدف ثبت دقیق تمام اندازهگیریها یا شمارش هر رخداد مستقل باشد، ازدسترفتن یک پیام میتواند اهمیت بیشتری داشته باشد.
مزایا و محدودیتها
مزیت اصلی سطح صفر، سادگی و سربار کمتر آن است.
در مقابل، پروتکل برای هر پیام تأیید دریافت ندارد.
بنابراین این سطح برای اطلاعاتی مناسب است که مرتباً تازه میشوند و ازدسترفتن یک نمونه، با توجه به نیاز واقعی پروژه، قابلقبول است.
۴. نحوه عملکرد سطح یک کیفیت سرویس
در سطح یک، دریافتکننده بسته انتشار را تأیید میکند.
این سطح با عبارت زیر شناخته میشود:
At least once
یعنی پروتکل با استفاده از سازوکار تأیید و ارسال مجدد، تحویل حداقل یکبار را در محدوده شرایط و تعهدات پروتکل دنبال میکند.
روش عملکرد
ابتدا فرستنده پیام را ارسال میکند:
PUBLISH
دریافتکننده پس از دریافت و پردازش در سطح پروتکل، پاسخ زیر را ارسال میکند:
PUBACK
پس از دریافت این پاسخ، فرستنده میتواند تبادل مربوط به آن پیام را تکمیلشده بداند.
چرا ممکن است پیام دوبار دریافت شود؟
فرض کنید بروکر پیام کنترلر را دریافت کرده است و پاسخ تأیید را ارسال میکند.
اما پیش از رسیدن پاسخ به کنترلر، ارتباط قطع میشود.
کنترلر نمیداند آیا پیام واقعاً دریافت شده است یا خیر.
با توجه به وضعیت نشست و قواعد بازیابی، ممکن است پیام دوباره ارسال شود.
در نتیجه، دریافتکننده ممکن است نسخه تکراری پیام را نیز دریافت کند.
مثال صنعتی
فرض کنید پیام مربوط به شمارنده تولید چنین باشد:
{"count":12540}
اگر این پیام دوبار دریافت شود و نرمافزار فقط آخرین مقدار شمارنده را ذخیره کند، معمولاً مشکلی ایجاد نمیشود.
اما اگر هر دریافت پیام به معنی افزودن یک بسته به تعداد تولید تلقی شود، دریافت تکراری میتواند گزارش نادرست ایجاد کند.
بنابراین نوع پردازش داده در برنامه اهمیت زیادی دارد.
نکته کاربردی
سطح یک برای بسیاری از پیامهای مهم صنعتی انتخاب مناسبی است، اما برنامه دریافتکننده باید احتمال تکرار را در نظر بگیرد.
۵. نحوه عملکرد سطح دو کیفیت سرویس
سطح دو، پیچیدهترین سازوکار تحویل پیام را در MQTT دارد.
این سطح با عبارت زیر شناخته میشود:
Exactly once
هدف این سطح، تحویل دقیقاً یکباره پیام کاربردی در محدوده ارتباط MQTT است.
برای این منظور، چهار مرحله کنترلی میان فرستنده و دریافتکننده اجرا میشود.
PUBLISH
PUBREC
PUBREL
PUBCOMP
ترتیب تبادل
فرستنده ابتدا پیام را منتشر میکند.
دریافتکننده با ارسال پیام دریافت، مرحله نخست را تأیید میکند.
سپس فرستنده پیام آزادسازی را ارسال میکند و دریافتکننده با پیام تکمیل، پایان تبادل را اعلام میکند.
این سازوکار به دو طرف کمک میکند حتی در شرایط ارسال مجدد بستههای کنترلی، از تحویل تکراری پیام کاربردی در سطح پروتکل جلوگیری کنند.
تفاوت تحویل دقیقاً یکبار با اجرای دقیقاً یکبار
فرض کنید نمایشگر فرمان روشنشدن موتور را منتشر کرده است.
پیام با سطح دو به کنترلر تحویل داده میشود و برنامه کنترلر درخواست را اجرا میکند.
اما پس از روشنشدن موتور، ارتباط قطع میشود و پاسخ کاربردی به نمایشگر نمیرسد.
اپراتور ممکن است تصور کند فرمان انجام نشده است و درخواست تازهای ارسال کند.
این درخواست جدید، پیام کاربردی مستقلی است و سازوکار سطح دو از اجرای مجدد آن جلوگیری نمیکند.
بنابراین حتی در این سطح باید از شناسه فرمان و منطق جلوگیری از اجرای تکراری استفاده شود.
۶. انتخاب سطح مناسب برای دادههای صنعتی
انتخاب کیفیت سرویس نباید فقط براساس این تصور انجام شود که سطح بالاتر همیشه بهتر است.
هر سطح، هزینه ارتباطی و پردازشی متفاوتی دارد.
برای مثال، اگر صدها سنسور هر ثانیه داده منتشر کنند، انتخاب سطح دو برای تمام اطلاعات ممکن است سربار غیرضروری ایجاد کند.
در مقابل، پیامهای مهمی که نباید بهآسانی از دست بروند، میتوانند به سازوکار تحویل قابلاعتمادتر نیاز داشته باشند.
جدول انتخاب پیشنهادی
| نوع اطلاعات | سطح پیشنهادی برای بررسی | توضیح |
| دمای لحظهای با انتشار مکرر | صفر یا یک | اگر ازدسترفتن یک نمونه قابلقبول باشد، سطح صفر کافی است. |
| فشار دورهای | صفر یا یک | وابسته به نیاز ثبت اطلاعات |
| وضعیت موتور | یک | احتمال تکرار باید مدیریت شود. |
| وضعیت آلارم | یک | نیازمند طراحی بازیابی و ثبت رخداد |
| شمارنده تجمعی تولید | یک | بهتر است مقدار مطلق ارسال شود. |
| رخداد شمارش هر محصول | یک یا دو | بدون شناسه کاربردی، خطر شمارش نادرست باقی میماند. |
| فرمان موتور | یک یا دو | پذیرش و اجرای واقعی باید جداگانه تأیید شود. |
این جدول پیشنهاد طراحی است و جای بررسی الزامات واقعی پروژه را نمیگیرد.
برای مثال، در سامانهای که ثبت تمام نمونههای یک آزمایش ضروری است، حتی سطح دو نیز بدون ذخیرهسازی محلی و سازوکار بازیابی کافی نخواهد بود.

۷. ارتباط تنظیم فرستنده با تنظیم اشتراک گیرنده
تا اینجا کیفیت سرویس را برای یک مسیر انتقال بررسی کردیم.
اما در مدل انتشار و اشتراک، یک پیام معمولاً از دو مسیر عبور میکند:
مسیر اول از فرستنده به بروکر و مسیر دوم از بروکر به مشترک.
سطح کیفیت سرویس در این دو مسیر الزاماً یکسان نیست.
فرض کنید کنترلر پیام را با سطح دو منتشر میکند، اما نمایشگر هنگام ثبت اشتراک، حداکثر سطح صفر را درخواست کرده است.
در این شرایط، بروکر پیام را برای نمایشگر با سطحی بالاتر از حداکثر سطح مجاز اشتراک ارسال نمیکند.
در نسخه ۳٫۱٫۱، سطح تحویل معمولاً از حداقل سطح انتشار اولیه و بیشینه سطح اعطاشده برای اشتراک تعیین میشود.
برای مثال:
| سطح انتشار | سطح اعطاشده اشتراک | سطح تحویل معمول |
| صفر | دو | صفر |
| یک | صفر | صفر |
| دو | یک | یک |
| یک | دو | یک |
در نسخه پنج، قواعد اشتراک و رفتار سرور امکانات بیشتری دارند و سطح تحویل میتواند براساس قواعد آن نسخه و سقف اشتراک تعیین شود.
بنابراین تنظیم فرستنده بهتنهایی تضمین نمیکند که گیرنده همان سطح کیفیت سرویس را دریافت کند.
نتیجه: در طراحی صنعتی باید سطح انتشار و اشتراک، هر دو مشخص و مستند شوند.
۸. نگهداری آخرین پیام با قابلیت ریتین
در بسیاری از پروژههای صنعتی، نمایشگر یا نرمافزار مانیتورینگ ممکن است پس از شروع کار کنترلر روشن شود.
فرض کنید کنترلر هر ده دقیقه وضعیت موتور را منتشر میکند. اگر نمایشگر تازه متصل شده باشد، آیا باید ده دقیقه منتظر پیام بعدی بماند؟
پروتکل MQTT قابلیتی برای نگهداری آخرین پیام منتشرشده یک موضوع فراهم میکند.
نام این قابلیت:
Retain
روش عملکرد
فرض کنید کنترلر وضعیت موتور را منتشر میکند:
factory/line1/motor01/status/running
محتوا:
{"running":true}
اگر هنگام انتشار، پرچم ریتین فعال باشد، بروکر آخرین پیام نگهداریشده این موضوع را حفظ میکند.
اکنون فرض کنید نمایشگر به بروکر متصل شده و اشتراک مناسب را ثبت کند.
بروکر میتواند آخرین پیام نگهداریشده منطبق را برای آن ارسال کند؛ حتی اگر موتور در همان لحظه تغییر وضعیت نداده باشد.
بهروزرسانی پیام
اگر وضعیت موتور تغییر کند و کنترلر پیام جدیدی را با پرچم ریتین منتشر کند، آخرین مقدار نگهداریشده برای آن موضوع جایگزین میشود.
برای مثال:
{"running":false}
بنابراین برای هر نام موضوع، آخرین پیام ریتینشده مبنای تحویل به مشترکان جدید است.
پاککردن پیام
در MQTT میتوان با انتشار پیام دارای محتوای صفر بایت و پرچم ریتین فعال، پیام ریتینشده یک موضوع را حذف کرد.
این عملیات را نباید با ارسال رشته خالی، یک شیء جیسون خالی یا مقدار تهی جیسون اشتباه گرفت.
برای مثال، محتوای زیر صفر بایت نیست:
{}
تفاوت پیام ریتینشده با آخرین مقدار واقعی
فرض کنید کنترلر دمای تابلو را با ریتین منتشر کرده است:
{"value":38.5}
سپس کنترلر خاموش میشود.
بروکر ممکن است همچنان آخرین پیام را نگهداری کند.
اگر نمایشگر پس از چند ساعت متصل شود، امکان دارد مقدار ۳۸٫۵ را دریافت کند؛ درحالیکه این مقدار دیگر نشاندهنده وضعیت فعلی تابلو نیست.
پس استفاده از ریتین برای دادههای صنعتی باید همراه روش تشخیص تازگی داده باشد.
نکته: پرچم ریتین هنگام انتشار و پرچم ریتین پیام تحویلی به گیرنده را باید با توجه به نسخه MQTT و قواعد اشتراک تفسیر کرد. هر پیام دریافتی که محتوای آن با آخرین مقدار نگهداریشده یکسان است، الزاماً یک ارسال اولیه ریتینشده به مشترک جدید نیست.

۹. تفاوت آخرین پیام با تاریخچه اطلاعات
یکی از اشتباهات رایج، یکسان دانستن قابلیت ریتین با ذخیره تاریخچه دادهها است.
فرض کنید سنسور دما در سه زمان مختلف مقدارهای زیر را منتشر کرده است:
| زمان | مقدار دما |
| ۱۰:۰۰ | ۳۸٫۵ |
| ۱۰:۰۵ | ۳۹٫۰ |
| ۱۰:۱۰ | ۳۹٫۴ |
اگر تمام این پیامها با پرچم ریتین منتشر شوند، بروکر در حالت معمول فقط آخرین پیام نگهداریشده را برای آن موضوع حفظ میکند.
بنابراین مشترک جدید نباید انتظار داشته باشد هر سه مقدار را بهعنوان تاریخچه دریافت کند.
ثبت تاریخچه
برای نگهداری تاریخچه، یک مصرفکننده اطلاعات باید پیامها را دریافت کرده و در سامانه ذخیرهسازی مناسب ثبت کند.
برای مثال، نرمافزار ثبت داده میتواند دمای تابلو را همراه زمان اندازهگیری در پایگاه داده ذخیره کند.
در این حالت، دو عملکرد مستقل داریم:
• ریتین برای ارائه آخرین پیام نگهداریشده به مشترک جدید
• پایگاه داده برای ثبت و بازیابی اطلاعات گذشته
خطر استفاده از ریتین برای فرمان
فرض کنید پیام روشنشدن موتور بهصورت ریتین منتشر شود.
factory/line1/motor01/cmd/run
{"value":true}
اگر کنترلر موتور بعداً اشتراک خود را دوباره ثبت کند، ممکن است همان فرمان قبلی را مجدداً دریافت کند.
این رفتار میتواند ناخواسته باشد.
به همین دلیل، برای فرمانهای اجرایی معمولاً نباید بدون طراحی دقیق اعتبار زمانی و جلوگیری از اجرای تکراری از ریتین استفاده کرد.
البته در برخی معماریها، وضعیت مطلوب یک تجهیز بهصورت پیام ماندگار طراحی میشود. در چنین شرایطی باید میان «وضعیت مطلوب» و «فرمان اجرایی یکباره» تفاوت صریح وجود داشته باشد.
۱۰. بررسی زندهبودن ارتباط
در یک ارتباط MQTT، ممکن است برای مدتی هیچ پیام کاربردی میان کلاینت و بروکر مبادله نشود.
برای مثال، سنسور درِ تابلو فقط هنگام باز یا بستهشدن وضعیت جدیدی منتشر میکند.
اگر درِ تابلو برای چند ساعت تغییر نکند، نبودن پیام الزاماً به معنی قطع ارتباط نیست.
پروتکل MQTT قابلیتی برای مدیریت این وضعیت دارد.
نام این ویژگی:
Keep Alive
نحوه عملکرد
هنگام برقراری اتصال، کلاینت فاصله زمانی مشخصی را برای نگهداری و بررسی ارتباط اعلام میکند.
اگر در این مدت بسته کنترلی MQTT دیگری ارسال نکرده باشد، کلاینت باید درخواست زیر را بفرستد:
PINGREQ
بروکر پاسخ میدهد:
PINGRESP
این تبادل به کلاینت کمک میکند وضعیت ارتباط خود با بروکر را بررسی کند.
مثال با زمان ۶۰ ثانیه
فرض کنیم مقدار تنظیمشده چنین باشد:
Keep Alive = 60 s
در این مثال، اگر کلاینت در بازه مربوط، بسته MQTT دیگری ارسال نکرده باشد، باید با ارسال درخواست بررسی، ارتباط را فعال نگه دارد.
اگر بروکر در مدت معادل یکونیم برابر مقدار تنظیمشده هیچ بسته کنترلی MQTT از کلاینت دریافت نکند، طبق قواعد پروتکل باید اتصال شبکه آن را قطع کند.
در مثال بالا:
1.5 × 60 = 90 ثانیه
این عدد را نباید زمان قطعی و تضمینشده تشخیص تمام خرابیهای شبکه دانست؛ زیرا وضعیت واقعی ارتباط، زمان آخرین بسته دریافتی و رفتار سیستمعامل و شبکه نیز مؤثرند.
تفاوت اتصال سالم با دستگاه سالم
فرض کنید یک دروازه ارتباطی از طریق اترنت به بروکر متصل است و دما را از یک ترانسمیتر مدباس میخواند.
اگر ارتباط مدباس قطع شود ولی دروازه همچنان به بروکر متصل باشد، تبادلهای بررسی ارتباط MQTT ممکن است کاملاً طبیعی ادامه پیدا کنند.
بنابراین:
زندهبودن اتصال MQTT به معنی سالمبودن ارتباط سنسور، کنترلر یا ماشین نیست.
در طراحی صنعتی بهتر است وضعیت ارتباط شبکه و وضعیت سلامت دادههای فرایند بهصورت مستقل بررسی شوند.
۱۱. اعلام قطع غیرعادی تجهیز با پیام وصیت
اگر ارتباط یک دستگاه بهصورت غیرمنتظره قطع شود، چگونه سایر کلاینتها متوجه شوند؟
پروتکل MQTT برای این موضوع قابلیت پیام وصیت را در نظر گرفته است.
نام آن:
Last Will and Testament
LWT
مفهوم پیام وصیت
هنگام اتصال، کلاینت میتواند از قبل موضوع و محتوای پیامی را به بروکر معرفی کند تا در شرایط مشخص قطع غیرعادی ارتباط، بروکر آن را منتشر کند.
برای مثال، کنترلر تابلوی اول میتواند موضوع زیر را تعیین کند:
factory/line1/panel01/connection
محتوای وصیت:
{"online":false}
اگر بروکر قطع غیرعادی کلاینت را تشخیص دهد و شرایط انتشار وصیت برقرار باشد، این پیام را منتشر میکند.
سامانههای مانیتورینگ میتوانند مشترک موضوع اتصال باشند.
اعلام آنلاینشدن
پس از برقراری اتصال موفق، خود کنترلر میتواند وضعیت آنلاین را منتشر کند:
{"online":true}
در یک طراحی متداول، پیام آنلاین و وصیت آفلاین هر دو با قابلیت ریتین منتشر میشوند.
در نتیجه، مشترک تازهمتصلشده نیز میتواند آخرین وضعیت اتصال اعلامشده را دریافت کند.
تفاوت قطع عادی و غیرعادی
اگر کلاینت با روش عادی پروتکل و پیام قطع ارتباط معمولی از بروکر جدا شود، پیام وصیت معمولاً منتشر نمیشود.
اما در شرایطی مانند قطع ناگهانی برق، خرابی شبکه یا ازدسترفتن ارتباط بدون قطع عادی، بروکر میتواند پس از تشخیص، پیام وصیت را منتشر کند.
در نسخه پنج، برخی حالتهای قطع ارتباط و تنظیمات پیام وصیت امکانات تکمیلی دارند.
محدودیت تشخیص قطعی
پیام وصیت الزاماً در همان لحظه خرابی فیزیکی منتشر نمیشود.
اگر کابل شبکه قطع شود، بروکر ابتدا باید قطع ارتباط را تشخیص دهد.
بنابراین اعلام آفلاین ممکن است با تأخیر انجام شود.
همچنین اگر خود بروکر از کار بیفتد، نمیتوان انتظار داشت همان بروکر در زمان خرابی خود پیام وصیت کلاینتها را توزیع کند.
مثال صنعتی
فرض کنید یک دروازه ارتباطی داده ده ترانسمیتر را جمعآوری میکند.
اگر خود دروازه خاموش شود، پیام وصیت میتواند قطع ارتباط آن را اعلام کند.
اما اگر تنها یکی از ترانسمیترهای زیرمجموعه خراب شود، دروازه همچنان آنلاین است.
در این حالت باید وضعیت ارتباط هر ترانسمیتر بهصورت داده کاربردی جداگانه گزارش شود.

۱۲. شناخت نشست ارتباطی و اطلاعات آن
برای درک رفتار سیستم هنگام قطع ارتباط، باید با مفهوم نشست آشنا شویم.
نام انگلیسی آن:
Session
نشست فقط به معنی برقرار بودن یک اتصال شبکه نیست.
در MQTT، نشست مجموعهای از اطلاعات مرتبط با ارتباط کلاینت و وضعیت تبادل پیامها است که میتواند طبق تنظیمات، پس از قطع اتصال نیز نگهداری شود.
اطلاعات نشست
بسته به نسخه پروتکل و شرایط ارتباط، اطلاعات نشست میتواند شامل مواردی مانند اشتراکهای ثبتشده و وضعیت پیامهای دارای کیفیت سرویس یک یا دو باشد که هنوز تبادل آنها کامل نشده است.
برای مثال، فرض کنید نمایشگر مشترک موضوع زیر است:
factory/line1/panel01/alarm/#
اگر نشست آن ماندگار باشد، امکان دارد پس از قطع ارتباط و اتصال مجدد با همان شناسه، اشتراک قبلی همچنان در نشست وجود داشته باشد.
تفاوت نشست با تاریخچه اطلاعات
نشست برای مدیریت وضعیت ارتباط و تحویل پیامها طراحی شده است.
اما تاریخچه دمای تابلو یا گزارش تولید یک روز کامل، بهطور خودکار جزو اطلاعات نشست محسوب نمیشود.
بنابراین نباید نشست ماندگار را جایگزین پایگاه داده یا ثبتکننده صنعتی دانست.
همچنین پیامهای ریتینشده، وضعیت جداگانهای در بروکر دارند و پایان یافتن یک نشست بهتنهایی به معنی حذف آنها نیست.
۱۳. مدیریت نشست در نسخههای مختلف پروتکل
نحوه تنظیم نشست در نسخههای مختلف MQTT تفاوتهایی دارد.
نسخه ۳٫۱٫۱
در این نسخه، گزینه زیر تعیینکننده رفتار اصلی نشست است:
Clean Session
اگر این گزینه فعال باشد، هنگام اتصال یک نشست تازه ایجاد میشود و نشست قبلی مربوط به شناسه کلاینت کنار گذاشته میشود.
اگر غیرفعال باشد، بروکر میتواند نشست موجود را با همان شناسه کلاینت ادامه دهد.
در این حالت، اشتراکها و پیامهای مرتبط با نشست طبق قواعد پروتکل نگهداری میشوند.
مثال نمایشگر
فرض کنید نمایشگر برای مدت کوتاهی ارتباط خود را از دست میدهد.
اگر نشست ماندگار و اشتراک مناسب با کیفیت سرویس یک یا دو وجود داشته باشد، پیامهای منطبق میتوانند در بروکر برای تحویل بعدی نگهداری شوند.
اما ظرفیت و سیاستهای اجرایی بروکر باید بررسی شوند.
نگهداری نشست، تضمین نامحدود ذخیره همه پیامها در هر شرایطی نیست.
نسخه پنج
در نسخه پنج، دو مفهوم جداگانه برای مدیریت نشست وجود دارد:
Clean Start
Session Expiry Interval
گزینه اول مشخص میکند اتصال جدید با نشست تازه آغاز شود یا امکان ادامه نشست قبلی وجود داشته باشد.
گزینه دوم تعیین میکند نشست پس از قطع ارتباط شبکه تا چه مدت نگهداری شود.
برای مثال:
Clean Start = 0
Session Expiry Interval = 3600
این تنظیم به معنی درخواست ادامه نشست موجود و نگهداری وضعیت نشست تا یک ساعت پس از قطع ارتباط است، مشروط به اینکه نشست قبلی وجود داشته و تنظیمات و سیاستهای سرور اجازه دهند.
اگر زمان انقضای نشست صفر باشد، نشست با بستهشدن ارتباط پایان مییابد.
در نسخه پنج، مقدار ویژهای نیز برای درخواست نشست بدون انقضای زمانی تعیین شده است؛ هرچند محدودیتهای منابع و سیاستهای مدیریتی سرور همچنان اهمیت دارند.
جدول مقایسه
| ویژگی | نسخه ۳٫۱٫۱ | نسخه ۵ |
| آغاز نشست جدید | Clean Session | Clean Start |
| نگهداری نشست بعد از قطعی | براساس Clean Session و سیاست سرور | Session Expiry Interval |
| تعیین زمان مشخص انقضای نشست | گزینه مستقل ندارد | دارد |
| ادامه اشتراکهای قبلی | در نشست ماندگار | در نشست معتبر باقیمانده |

۱۴. اتصال مجدد پس از قطعی شبکه
قطع ارتباط در سامانههای صنعتی رویداد غیرمعمولی نیست.
ممکن است سوییچ شبکه راهاندازی مجدد شود، ارتباط اینترنت برای مدتی قطع شود یا تجهیزات به علت نوسان تغذیه از شبکه جدا شوند.
بنابراین برنامه کلاینت باید برای بازیابی ارتباط طراحی شده باشد.
روش نامناسب اتصال مجدد
فرض کنید پس از قطع شبکه، کنترلر در یک حلقه برنامه بدون فاصله تلاش میکند دوباره به بروکر متصل شود.
اگر تعداد زیادی کنترلر همین رفتار را داشته باشند، ممکن است بار غیرضروری روی شبکه و بروکر ایجاد شود.
همچنین برنامه کنترلر نباید در تلاشهای اتصال مجدد، اجرای وظایف اصلی ماشین را متوقف کند.
روش مناسب
یک روش متداول این است که فاصله تلاشهای مجدد بهصورت تدریجی افزایش یابد.
برای مثال:
1 s
2 s
4 s
8 s
16 s
30 s
این اعداد صرفاً نمونه هستند و باید با مشخصات شبکه و تجهیزات هماهنگ شوند.
در پروژههای بزرگ، افزودن تغییر تصادفی محدود به فاصله تلاشها میتواند از اتصال همزمان تعداد زیادی دستگاه جلوگیری کند.
بازیابی وضعیت برنامه
پس از اتصال مجدد، کنترلر باید بررسی کند که آیا نشست قبلی ادامه یافته یا نشست جدیدی ایجاد شده است.
اگر اشتراکهای قبلی وجود نداشته باشند، باید دوباره ثبت شوند.
همچنین بهتر است کنترلر اطلاعات وضعیت جاری خود را منتشر کند.
برای مثال، اگر موتور در زمان قطعی خاموش شده باشد، نمایشگر پس از بازیابی ارتباط باید وضعیت واقعی تازه را دریافت کند؛ نه اینکه فقط به وضعیت پیش از قطعی تکیه کند.
۱۵. تفاوت صف بروکر با ذخیره محلی داده
فرض کنید یک دروازه صنعتی هر ده ثانیه دمای پنج سنسور را منتشر میکند.
اگر ارتباط دروازه با بروکر به مدت یک ساعت قطع شود، چه اتفاقی برای اندازهگیریهای این مدت خواهد افتاد؟
پاسخ به ساختار سیستم بستگی دارد.
صف پیام در بروکر
اگر یک مشترک از بروکر قطع شده باشد، بروکر ممکن است پیامهای مشخصی را طبق وضعیت نشست، کیفیت سرویس و محدودیتهای خود برای تحویل بعدی نگهداری کند.
اما این وضعیت زمانی کاربرد دارد که پیامها به بروکر رسیده باشند.
اگر خود فرستنده نتواند به بروکر دسترسی پیدا کند، صف بروکر بهتنهایی نمیتواند دادههایی را ذخیره کند که هرگز به آن نرسیدهاند.
ذخیره محلی در فرستنده
برای جلوگیری از ازدسترفتن داده در زمان قطع ارتباط، میتوان ذخیرهسازی محلی را در کنترلر یا دروازه ارتباطی طراحی کرد.
برای مثال، هر اندازهگیری در حافظه غیرفرار یا حافظه ذخیرهسازی مناسب ثبت شود.
پس از بازیابی ارتباط، دستگاه میتواند اطلاعات ثبتشده را با ترتیب و نرخ مناسب ارسال کند.
مثال
فرض کنیم هر ده ثانیه یک اندازهگیری ثبت میشود.
در یک ساعت تعداد نمونههای هر سنسور برابر است با:
3600 ÷ 10 = 360
اگر پنج سنسور داشته باشیم:
360 × 5 = 1800
بنابراین در یک ساعت قطعی، ۱۸۰۰ مقدار اندازهگیریشده تولید میشود.
برای نگهداری آنها باید ظرفیت حافظه، اندازه هر رکورد و سربار ثبت اطلاعات بررسی شود.
نکته اجرایی
در زمان اتصال مجدد، ارسال ناگهانی تمام اطلاعات ذخیرهشده ممکن است بار زیادی ایجاد کند.
بهتر است برنامه برای ارسال تدریجی، تفکیک داده تاریخی از داده جاری و تشخیص پیامهای تکراری طراحی شود.
همچنین هنگام استفاده از حافظه فلش، تعداد نوشتنها و طول عمر حافظه باید لحاظ شود.
۱۶. مدیریت پیام تکراری، قدیمی و خارج از ترتیب مورد انتظار
در یک سیستم صنعتی، دریافت موفق پیام بهتنهایی برای استفاده از آن کافی نیست.
برنامه ممکن است پیامی تکراری، قدیمی یا خارج از ترتیب مورد انتظار دریافت کند.
پیام تکراری
فرض کنید شمارنده تولید مقدار زیر را منتشر کرده است:
{
"count": 12540,
"seq": 125
}
اگر همان پیام دوباره دریافت شود، برنامه باید بتواند آن را تشخیص دهد.
یک روش، استفاده از شماره ترتیب است.
پیام قدیمی
فرض کنید پیام دارای زمان اندازهگیری زیر باشد:
{
"value": 38.5,
"timestamp": "2026-10-17T10:30:00Z"
}
اگر این پیام چند ساعت بعد دریافت شود، ممکن است برای نمایش دمای فعلی مناسب نباشد.
در این حالت باید زمان اندازهگیری با زمان معتبر سامانه مقایسه شود.
پیام خارج از ترتیب
فرض کنید دو پیام به ترتیب اندازهگیری زیر تولید شدهاند:
seq = 125
seq = 126
اما نرمافزار ابتدا پیام ۱۲۶ و سپس پیام ۱۲۵ را دریافت کند.
اگر بدون بررسی، هر پیام جدید مقدار قبلی نمایشگر را جایگزین کند، ممکن است داده قدیمیتر پس از داده تازهتر نمایش داده شود.
میتوان با بررسی شماره ترتیب و زمان اندازهگیری، از چنین خطاهایی جلوگیری کرد.
البته شماره ترتیب باید به یک منبع مشخص وابسته باشد و رفتار آن هنگام راهاندازی مجدد تعریف شود.
محدودیت ترتیب بین چند فرستنده
اگر دو کنترلر مستقل پیام منتشر کنند، نمیتوان فقط با شماره ترتیب داخلی هرکدام یک ترتیب زمانی جهانی تعیین کرد.
برای تحلیل رویدادهای چند دستگاه، ساعتهای هماهنگ، شناسه منبع و قرارداد مناسب ترتیب رخداد لازم است.
۱۷. قابلیتهای تکمیلی نسخه پنج برای کاربرد صنعتی
نسخه پنج MQTT امکاناتی دارد که بعضی مشکلات ارتباطی را سادهتر مدیریت میکنند.
در این بخش با چند قابلیت مهم آشنا میشویم.
انقضای پیام
Message Expiry Interval
با این ویژگی، فرستنده میتواند مدت اعتبار پیام را در سطح پروتکل مشخص کند.
فرض کنید پیام دمای لحظهای فقط برای ۳۰ ثانیه مفید باشد.
میتوان زمان انقضای مناسب تعیین کرد تا پیام پس از سپریشدن مدت مقرر، در صف تحویل باقی نماند.
این ویژگی برای دادههایی که پس از مدت کوتاه ارزش خود را از دست میدهند مفید است.
البته اعتبار فرایندی داده و شرایط ایمنی همچنان باید در برنامه بررسی شوند.
تأخیر پیام وصیت
Will Delay Interval
گاهی ارتباط یک تجهیز برای چند ثانیه قطع شده و سریعاً بازیابی میشود.
در چنین شرایطی ممکن است نخواهیم سیستم مانیتورینگ برای هر قطعی بسیار کوتاه هشدار آفلاین صادر کند.
نسخه پنج امکان تعریف تأخیر برای انتشار پیام وصیت را فراهم میکند.
اگر شرایط ادامه نشست و اتصال مجدد طبق قواعد پروتکل برقرار شوند، انتشار وصیت میتواند لغو شود.
این ویژگی باید همراه زمان انقضای نشست طراحی شود؛ زیرا پایان نشست میتواند موجب انتشار زودتر پیام وصیت شود.
کدهای علت
Reason Codes
در نسخه پنج، اطلاعات دقیقتری درباره نتیجه بسیاری از عملیات پروتکل در اختیار کلاینت قرار میگیرد.
این موضوع برای عیبیابی مفید است.
برای مثال، برنامه ممکن است بتواند میان بعضی خطاهای مربوط به مجوز، قالب بسته یا محدودیتهای سرویس تفاوت قائل شود.
اطلاعات درخواست و پاسخ
Response Topic
Correlation Data
این ویژگیها امکان قراردادن اطلاعات تکمیلی مرتبط با الگوی درخواست و پاسخ را فراهم میکنند.
برای مثال، فرستنده میتواند مشخص کند پاسخ درخواست به چه موضوعی ارسال شود و چه دادهای برای ارتباطدادن پاسخ با درخواست استفاده شود.
با این حال، خود MQTT منطق اجرای فرمان، مهلت اعتبار درخواست یا تأیید عملکرد فیزیکی تجهیز را تعیین نمیکند.
این موارد همچنان باید در برنامه کاربردی پیادهسازی شوند.
۱۸. طراحی فرمان قابلپیگیری و جلوگیری از اجرای دوباره
اکنون مفاهیم فصل را در یک مثال کامل به کار میگیریم.
فرض کنید نمایشگر مرکزی باید بتواند درخواست روشنشدن موتور شماره یک را ارسال کند.
برای جلوگیری از اشتباه، تصمیم میگیریم هر فرمان دارای شناسه یکتا، زمان ایجاد و مدت اعتبار باشد.
مرحله اول: ساخت فرمان
موضوع:
factory/line1/motor01/cmd/run
محتوا:
{
"command_id": "CMD-12540",
"value": true,
"timestamp": "2026-10-17T10:30:00Z",
"valid_for_ms": 5000
}
در این پیام، شناسه فرمان مشخص میکند درخواست متعلق به کدام عملیات است.
زمان و مدت اعتبار نیز امکان بررسی قدیمیبودن درخواست را فراهم میکنند.
کنترلر باید از ساعت معتبر یا روش مناسب دیگری برای سنجش اعتبار زمانی استفاده کند.
مرحله دوم: دریافت و بررسی
کنترلر پس از دریافت پیام باید موارد زیر را بررسی کند:
۱. آیا قالب پیام معتبر است؟
۲. آیا شناسه فرمان قبلاً پردازش شده است؟
۳. آیا فرمان هنوز اعتبار دارد؟
۴. آیا فرستنده مجوز لازم را دارد؟
۵. آیا وضعیت محلی دستگاه اجازه اجرای فرمان را میدهد؟
۶. آیا حفاظتها و اینترلاکها برقرار هستند؟
اعتبارسنجی هویت و مجوزها باید با ساختار امنیتی پروژه هماهنگ باشد؛ وجود یک شناسه در محتوای پیام بهتنهایی مجوز اجرای فرمان ایجاد نمیکند.
مرحله سوم: اعلام نتیجه بررسی
اگر فرمان پذیرفته شود، کنترلر میتواند پاسخ زیر را منتشر کند.
factory/line1/motor01/response/run
{
"command_id": "CMD-12540",
"accepted": true,
"status": "accepted"
}
این پاسخ فقط پذیرش درخواست را اعلام میکند، نه روشنشدن واقعی موتور را.
مرحله چهارم: اجرای فرمان
کنترلر پس از بررسی شرایط، خروجی راهاندازی موتور را فعال میکند.
برای مثال، فرمان به درایو یا کنتاکتور ارسال میشود.
مرحله پنجم: بررسی بازخورد
پس از اجرای درخواست، کنترلر باید نتیجه واقعی را از ورودی یا وضعیت معتبر دستگاه تشخیص دهد.
اگر موتور روشن شده باشد، میتوان پیام زیر را منتشر کرد:
{
"command_id": "CMD-12540",
"status": "completed",
"running": true
}
اگر موتور روشن نشده باشد، پاسخ باید نتیجه واقعی را نشان دهد.
{
"command_id": "CMD-12540",
"status": "failed",
"reason": "drive_fault"
}
جلوگیری از اجرای دوباره
فرض کنید کنترلر فرمان را اجرا کرده است، ولی پاسخ به نمایشگر نمیرسد.
نمایشگر ممکن است پس از مهلت انتظار، همان درخواست را دوباره ارسال کند.
اگر شناسه فرمان ثابت مانده باشد، کنترلر میتواند تشخیص دهد این درخواست قبلاً پردازش شده است.
در چنین شرایطی، بهجای اجرای دوباره، میتواند آخرین نتیجه ثبتشده همان شناسه را اعلام کند.
این روش برای فرمانهایی که تکرار آنها خطرناک یا نامطلوب است اهمیت ویژهای دارد.
برای مثال، اگر فرمان «افزایش شمارنده به اندازه یک واحد» دوبار اجرا شود، نتیجه با فرمان «قرار دادن شمارنده روی مقدار مشخص» تفاوت دارد.
بنابراین طراحی فرمانها به شکلی که اجرای تکراری آنها اثر ناخواسته نداشته باشد، میتواند قابلیت اطمینان سیستم را افزایش دهد.
جدول وضعیت فرمان
| وضعیت | معنی |
| received | پیام در برنامه دریافت شده است. |
| accepted | درخواست معتبر و مجاز شناخته شده است. |
| rejected | درخواست رد شده است. |
| executing | عملیات در حال اجراست. |
| completed | نتیجه واقعی مورد انتظار تأیید شده است. |
| failed | عملیات انجام نشده یا نتیجه تأیید نشده است. |
| expired | اعتبار درخواست به پایان رسیده است. |
این وضعیتها قراردادی هستند و خود پروتکل MQTT آنها را ایجاد نمیکند.
نکته ایمنی
فرمانهای مربوط به توقف اضطراری، حفاظت ماشین و سایر وظایف ایمنی نباید صرفاً به رسیدن پیام از شبکه MQTT وابسته باشند.
منطق ایمنی و حفاظت باید مطابق الزامات کاربرد صنعتی، مستقل و دارای رفتار قابلپیشبینی در شرایط خرابی ارتباط باشد.

جمعبندی فصل سوم
در این فصل آموختیم که قابلیت اطمینان ارتباط MQTT تنها به ارسال موفق پیام محدود نمیشود.
سه سطح کیفیت سرویس، روشهای متفاوتی برای تحویل پیام فراهم میکنند، اما هیچیک بهتنهایی نمیتوانند اجرای واقعی فرمان یا اعتبار داده سنسور را تضمین کنند.
همچنین دیدیم که قابلیت ریتین امکان دریافت آخرین پیام نگهداریشده را فراهم میکند، ولی جایگزین تاریخچه اطلاعات نیست.
با مفهوم بررسی زندهبودن ارتباط و پیام وصیت نیز آشنا شدیم و دریافتیم که قطع ارتباط MQTT با خرابی تجهیزات پاییندست تفاوت دارد.
در ادامه، مدیریت نشست، اتصال مجدد، صف پیام و ذخیره محلی اطلاعات را بررسی کردیم.
در پایان نیز روشی برای طراحی فرمان قابلپیگیری ارائه شد که از شناسه فرمان، زمان اعتبار، پاسخ کاربردی و بازخورد واقعی استفاده میکند.
مهمترین نتیجه این فصل آن است که:
اطمینان از تحویل پیام، اطمینان از پردازش پیام و اطمینان از انجام واقعی فرمان، سه موضوع متفاوت هستند و هرکدام باید در جای مناسب خود طراحی و بررسی شوند.
ارتباط با فصل چهارم
در فصل چهارم، مفاهیم سه فصل گذشته را در یک پروژه صنعتی به کار خواهیم گرفت.
در آن پروژه، کنترلر، تجهیزات مدباس، دروازه ارتباطی، بروکر، اچامآی و سامانه ثبت اطلاعات را به یکدیگر متصل میکنیم.
سپس با ایجاد خطاهای عمدی، قطع ارتباط و ارسال پیامهای نامعتبر، رفتار سیستم را آزمایش خواهیم کرد.
در نهایت، موضوعهای امنیت ارتباط، تعیین مجوز کاربران، عیبیابی و آزمون تحویل پروژه بررسی خواهند شد.
دیدگاه خود را بنویسید