# تشريح وحدة SMPP PDU: الترويسة والجسم

> كل رسالة SMPP هي وحدة PDU (وحدة بيانات البروتوكول) بترويسة ثابتة طولها 16 بايت يتبعها جسم خاص بالعملية. الترويسة أربعة أعداد صحيحة بطول 4 بايت بترتيب big-endian: command_length وcommand_id وcommand_status وsequence_number. ويحصي command_length كامل الوحدة بما فيها الترويسة، لذا يقرأ المستقبِل 4 بايت أولًا ثم البقية.

- الرابط الأساسي: https://www.broadnet.me/ar/reference/smpp-pdu-anatomy
- اللغة: ar
- آخر تحديث: 2026-07-18
- الناشر: BroadNet (https://www.broadnet.me)

التخطيط البايتي الدقيق لوحدة SMPP PDU: ترويسة الـ 16 بايت (command_length، command_id، command_status، sequence_number)، والجسم، وكيف تُرمَّز الحقول.

## ترويسة الـ 16 بايت

تبدأ كل وحدة PDU بالأعداد الصحيحة الأربعة نفسها بطول 32 بت غير مؤشَّرة بترتيب بايت الشبكة (big-endian). وقيمة command_length هي إجمالي عدد البايتات في الوحدة بما فيها بايتات الترويسة الـ 16 — يقرأ المحلِّل أول 4 بايت، ويعرف الطول الكامل، ثم يقرأ البقية. ويحدّد command_id العملية. أما command_status فيساوي 0 (ESME_ROK) في الطلبات ويحمل رمز خطأ في الاستجابات. ويربط sequence_number الطلب باستجابته.

*حقول ترويسة SMPP (16 بايت، big-endian)*

| الإزاحة | الحقل | الحجم | الغرض |
|---|---|---|---|
| 0 | command_length | 4 octets | إجمالي طول PDU بالأوكتيت، بما في ذلك الترويسة |
| 4 | command_id | 4 octets | معرف العملية (مثلاً submit_sm = 0x00000004) |
| 8 | command_status | 4 octets | 0 في الطلب؛ رمز خطأ في الاستجابة |
| 12 | sequence_number | 4 octets | يربط الطلب↔الاستجابة (0x00000001–0x7FFFFFFF) |

## command_id وبتّ الاستجابة

لكل عملية قيمة command_id. وتستخدم الاستجابة المقابلة القيمة نفسها مع ضبط البتّ الأعلى قيمةً (عملية OR منطقية مع 0x80000000). فمثلًا submit_sm هو 0x00000004 وsubmit_sm_resp هو 0x80000004. أما generic_nack (0x80000000) فهو استجابة الخطأ الشاملة لأي وحدة PDU غير قابلة للتحليل أو غير صالحة.

*قيم command_id الشائعة*

| العملية | الطلب | الاستجابة |
|---|---|---|
| generic_nack | — | 0x80000000 |
| bind_receiver | 0x00000001 | 0x80000001 |
| bind_transmitter | 0x00000002 | 0x80000002 |
| query_sm | 0x00000003 | 0x80000003 |
| submit_sm | 0x00000004 | 0x80000004 |
| deliver_sm | 0x00000005 | 0x80000005 |
| unbind | 0x00000006 | 0x80000006 |
| replace_sm | 0x00000007 | 0x80000007 |
| cancel_sm | 0x00000008 | 0x80000008 |
| bind_transceiver | 0x00000009 | 0x80000009 |
| enquire_link | 0x00000015 | 0x80000015 |
| data_sm | 0x00000103 | 0x80000103 |

## الجسم وكيفية ترميز الحقول

بعد الترويسة يأتي الجسم الخاص بالعملية من المعاملات الإلزامية، متبوعًا اختياريًا بمعاملات TLV الاختيارية. ويستخدم SMPP ثلاثة أنواع من ترميز الحقول. الأعداد الصحيحة ثابتة الحجم وغير مؤشَّرة وبترتيب big-endian. وسلاسل C-Octet String نصوص ASCII منتهية ببايت NULL (0x00)، بطول أقصى مُعلَن يشمل حرف الإنهاء. أما Octet Strings فهي حقول بايتات خام يُعطى طولها بحقل طول سابق (مثل short_message الذي يُضبَط حجمه بـ sm_length).

*ترميزات حقول SMPP*

| النوع | الترميز |
|---|---|
| Integer | ثابت بطول 1/2/4 أوكتيت، بلا إشارة، big-endian (ترتيب بايتات الشبكة) |
| C-Octet String | ASCII منتهية بـ NUL؛ الحد الأقصى للطول يشمل مُنهي السلسلة 0x00 |
| C-Octet String (Decimal/Hex) | كما سبق، ولكن يقتصر على الأرقام العشرية أو الست عشرية ASCII |
| Octet String | بايتات خام؛ يحدد الطول حقلُ طول منفصل، بلا مُنهٍ |

## مثال محلول: submit_sm على السلك

وحدة submit_sm بحدها الأدنى. قيمة command_length في الترويسة (0x0000003D = 61) هي إجمالي عدد البايتات؛ وcommand_id بقيمة 0x00000004 هو submit_sm؛ وcommand_status بقيمة 0 يعني طلبًا؛ وsequence_number بقيمة 0x0000000F يربط الاستجابة. ثم يتبع الجسم بترتيب الحقول الثابت المحدَّد في المواصفة.

*ترويسة submit_sm وبداية الجسم (موضّحة)*

```hex
00 00 00 3D   command_length = 61
00 00 00 04   command_id     = submit_sm
00 00 00 00   command_status = ESME_ROK (request)
00 00 00 0F   sequence_number = 15
-- body --
00            service_type    = "" (NULL)
05            source_addr_ton = 5 (alphanumeric)
00            source_addr_npi = 0 (unknown)
42 4E 00      source_addr     = "BN" + NULL
01            dest_addr_ton   = 1 (international)
01            dest_addr_npi   = 1 (E.164/ISDN)
...           destination_addr, esm_class, ... short_message
```

## الأسئلة الشائعة

### هل يشمل command_length الترويسة؟

نعم. قيمة command_length هي الطول الكلي لكامل وحدة PDU بالبايت، بما فيها ترويسة الـ 16 بايت. يقرأ المستقبِل عددًا من البايتات يساوي command_length تمامًا لاستهلاك وحدة PDU كاملة من تدفق TCP.

### ما ترتيب البايت الذي يستخدمه SMPP؟

ترتيب بايت الشبكة — big-endian — لجميع حقول الأعداد الصحيحة متعددة البايتات، بما فيها كل حقل في الترويسة. فقيمة من 4 بايت تساوي 61 تُرسَل بالشكل ⁦00 00 00⁩ 3D.

### كيف تُنهى الحقول النصية؟

الحقول النصية هي سلاسل C-Octet String: محارف ASCII منتهية ببايت NULL واحد (0x00). والسلسلة C-Octet String الفارغة هي بايت NULL وحده. ويشمل الطول الأقصى المُعلَن حرف الإنهاء هذا.

### ما هو generic_nack؟

generic_nack (رمز العملية 0x80000000) هو الاستجابة التي يعيدها المستقبِل عندما يتعذّر تحليل وحدة PDU أو تكون غير صالحة جوهريًا — مثل command_length خاطئ أو command_id غير معروف. ويحمل command_status الخاص به السبب.

### كيف يؤطِّر المستقبِل وحدات PDU على تدفق TCP؟

TCP تدفق بايتات بلا حدود رسائل، لذا يقرأ المستقبِل أول 4 بايت للحصول على command_length، ثم يقرأ ذلك العدد الكلي من البايتات لعزل وحدة PDU كاملة قبل تحليل بقية الترويسة والجسم.

## المصادر

- [SMPP v3.4 specification — §2, §3 PDU format](https://smpp.org/SMPP_v3_4_Issue1_2.pdf)
- [SMPP v5.0 specification](https://smpp.org/SMPP_v5.pdf)

## ذو صلة

- [نظرة عامة على بروتوكول SMPP](https://www.broadnet.me/ar/reference/smpp-protocol-overview)
- [مفكّك SMPP PDU (أداة مجانية)](https://www.broadnet.me/ar/tools/smpp-pdu-decoder)
- [معاملات SMPP TLV الاختيارية](https://www.broadnet.me/ar/reference/smpp-tlv-parameters)
- [رموز أخطاء SMPP command_status](https://www.broadnet.me/ar/reference/smpp-command-status-errors)
- [توثيق المطوّرين](https://www.broadnet.me/ar/developers)
