← مجموعه مستندات پروژه
PCAP ANALYSIS · PURE CORE · KAFKA PUBLISH

زیرسیستم استخراج اطلاعات شبکه‌ای (Network Analyzer)

تحلیل فایل‌های PCAP ضبط‌شده با PCAPdroid برای اپ‌های پیام‌رسان (سناریوهای آپلود و دانلود)، محاسبهٔ شاخص‌های کیفیت و حجم شبکه، و انتشار نتیجه به Kafka — بدون اتصال مستقیم به PostgreSQL.

Pure coreanalysis/ بدون I/O
9 metricsکیفیت TCP + حجم IP
Kafka onlyبدون Postgres
200+ testsUnit · Oracle · Live

این مستند معماری، فلوی اجرا، متدولوژی ضبط داده، تعریف دقیق شاخص‌ها، و تصمیمات مهندسی زیرسیستم تحلیل ترافیک شبکه را شرح می‌دهد. این زیرسیستم فایل‌های PCAP ضبط‌شده با PCAPdroid را برای اپلیکیشن‌های دسته‌ی گپ‌وگفت (در دو سناریوی آپلود و دانلود) تحلیل می‌کند، شاخص‌های کیفیت و حجم شبکه را محاسبه می‌کند، و نتیجه را به تاپیک network-metrics در Kafka منتشر می‌کند.

نقش آن در زنجیرهٔ داده مکمل Crawler است: یکی آمار و نقد Play Store را می‌آورد، دیگری کیفیت شبکهٔ واقعی روی گوشی را می‌سنجد. ماندگارسازی هر دو مسیر را Storage Consumer انجام می‌دهد.

۱ تصمیم معماری بنیادین: هسته‌ی تحلیل کاملاً خالص و مستقل از I/O

مهم‌ترین تصمیم طراحی این زیرسیستم است: پوشه‌ی analysis/ فقط به dpkt، کتابخانه‌ی استاندارد پایتون، و مدل دامنه (core/models.py) وابسته است — هیچ‌گاه Kafka، HTTP، یا Config را import نمی‌کند. این تفکیک دقیقاً همان چیزی است که اجازه داد Milestoneهای خواندن پکت و محاسبه‌ی شاخص‌ها کاملاً بدون روشن بودن هیچ زیرساختی (نه Kafka، نه App API) ساخته و با صدها Synthetic PCAP تست شوند.

flowchart TB subgraph Pure["هسته‌ی خالص — بدون I/O"] PR[packet_reader.py
DLT dispatch + PCAPdroid trailer strip] TCP[tcp_analyzer.py
RTT, Retrans, OOO, Spurious, ZWin, RST] VOL[volume_analyzer.py
Bytes Total, Payload] MC[metrics_calculator.py
ترکیب + Overhead Ratio] PR --> TCP PR --> VOL TCP --> MC VOL --> MC end subgraph IO["لایه‌های I/O"] MSG[messaging/kafka_publisher.py] CLI[clients/app_registry_client.py] RT[runtime/analyzer_service.py] end MC --> RT RT --> CLI RT --> MSG style Pure fill:#16a34a,color:#fff style IO fill:#2563eb,color:#fff
پیامد عملی: چون analysis/ هیچ وابستگی بیرونی ندارد، بیش از ۲۰۰ تست Unit و تست‌های Oracle در کمتر از چند ثانیه اجرا می‌شوند، بدون نیاز به هیچ کانتینر یا بروکری. همین مرز، پایهٔ استراتژی تست سه‌لایه در بخش ۱۱ است.

۲ ساختار پوشه (پس از بازآرایی معماری)

مطابق همان الگوی معماری که در storage_consumer پیاده‌سازی شد (جداسازی بر اساس مسئولیت و جهت وابستگی)، ساختار نهایی این زیرسیستم چنین است:

flowchart TD Main["main.py
(CLI + Composition Root)"] --> Config[config.py] Main --> Runtime["runtime/analyzer_service.py
validate → analyze → publish"] Runtime --> Core["core/
models.py, message_mapper.py,
filename_parser.py"] Runtime --> Analysis["analysis/
هسته‌ی خالص"] Runtime --> Messaging["messaging/
kafka_publisher.py"] Runtime --> Clients["clients/
app_registry_client.py"] Runtime --> Common["common/
retry_policy.py"] style Analysis fill:#16a34a,color:#fff style Core fill:#7c3aed,color:#fff style Messaging fill:#f59e0b,color:#fff style Clients fill:#f59e0b,color:#fff
ANALYSIS

هستهٔ خالص

packet_reader، tcp_analyzer، volume_analyzer، metrics_calculator — فقط پکت به متریک؛ بدون شبکه.

CORE

دامنه و قرارداد

مدل‌های immutable، پارسر نام فایل، و message_mapper خالص که شکل JSON تاپیک را تعریف می‌کند.

I/O

messaging + clients

دو نوع ارتباط بیرونی عمداً جدا شده‌اند: Kafka برای خروجی، HTTP برای اعتبارسنجی App API.

RUNTIME

Composition Root

main.py اشیاء واقعی را می‌سازد؛ analyzer_service use-case را اجرا می‌کند: validate → analyze → publish.

نکته‌ی طراحی: برخلاف storage_consumer که فقط یک نوع I/O بیرونی (Kafka) داشت، این زیرسیستم دو نوع کاملاً متفاوت دارد — Kafka (خروجی نتیجه) و HTTP به App API (اعتبارسنجی اپلیکیشن) — که عمداً در دو پوشه‌ی جدا (messaging/ و clients/) نگه داشته شده‌اند، چون ماهیت و الگوی خطای این دو نوع ارتباط با هم فرق دارد.

۳ متدولوژی ضبط: از گوشی تا فایل PCAP قابل تحلیل

صحت اندازه‌گیری، پیش از هر خط کد، به نحوه‌ی ضبط بستگی دارد. سه اصل رعایت شده است:

flowchart TD A["اپ را Force Stop کن
(نه فقط بستن از Recent Apps)"] --> B["دلیل: اتصال Persistent/Keep-Alive
ممکن است زنده بماند و Handshake از دست برود"] B --> C["ضبط PCAPdroid را شروع کن"] C --> D["اپ را باز کن (Handshake اینجا ثبت می‌شود)"] D --> E["صبر کوتاه تا ترافیک Cold Start
(Sync، Auth، Presence) آرام بگیرد"] E --> F["فقط حالا عملیات هدف
(ارسال/دریافت فایل) را انجام بده"] F --> G["بلافاصله ضبط را متوقف کن"] style A fill:#dc2626,color:#fff style F fill:#16a34a,color:#fff
ملاحظهتوضیح
چرا Force Stop لازم است اکثر اپ‌های پیام‌رسان از اتصال TCP پایدار برای Push Notification استفاده می‌کنند؛ بدون Force Stop، ممکن است اصلاً Handshake جدیدی در Capture ثبت نشود و rtt_handshake برابر null بماند.
Trade-off اجتناب‌ناپذیر برای ثبت Handshake، ضبط باید از لحظه‌ی باز شدن اپ شروع شود؛ این یعنی مقداری ترافیک راه‌اندازی (Login/Sync/Presence) وارد فایل می‌شود که در bytes_transferred_total منعکس می‌شود. این محدودیت به‌جای حذف کامل، صادقانه در تفسیر نتایج ذکر می‌شود.
محدودیت شناخته‌شده‌ی دیگر متریک‌های کیفیت (RTT، Retransmission، Out-of-order، Spurious، Zero-Window، RST) فقط TCP هستند؛ متریک‌های حجم کل ترافیک IP از جمله QUIC/UDP را شامل می‌شوند. یک اپ مبتنی بر QUIC می‌تواند حجم بالا و Retransmission نزدیک صفر نشان دهد — این رفتار طبیعی پروتکل است، نه نقص Parser.
قرارداد نام فایل <package>__<upload|download>__<YYYYMMDDTHHMMSS>.pcap — جداکنندهٔ دو زیرخط چون . و _ داخل نام پکیج اندروید مجازند. timestamp فقط اطلاعاتی است و به قرارداد Kafka نمی‌رسد (ساعت گوشی قابل اعتماد نیست).
یک سناریو در هر فایل هر Capture دقیقاً یک عملیات هدف (ارسال یا دریافت فایل) دارد. Target apps در PCAPdroid روی همان اپ تنظیم شود تا ترافیک دیگران مخلوط نشود.

۴ تعریف دقیق شاخص‌ها — قطعی در برابر Heuristic

تفکیک صادقانه‌ی این‌که کدام شاخص خواندن مستقیم یک فیلد پروتکل است و کدام یک تخمین مهندسی‌شده، برای اعتبار علمی نتایج ضروری است. گروه ۱ فقط TCP را می‌بیند؛ گروه ۲ همه‌ی ترافیک IP را.

گروه ۱ — کیفیت و پایداری شبکه (فقط TCP)

شاخصنوعتعریف دقیق
rtt_handshake قطعی، با قرارداد خاص پروژه میانگین t(SYN-ACK) − t(SYN اولیه) بر حسب میلی‌ثانیه. عمداً از اولین SYN حساب می‌شود، نه آخرین تلاش — چون تعریف سند («از بسته‌ی اولیه») می‌خواهد افت و تاخیر ناشی از بسته‌های گم‌شده در عدد نهایی منعکس شود، برخلاف الگوریتم کلاسیک Karn که چنین نمونه‌ای را کنار می‌گذارد. این متریک صرفاً سطح TCP را می‌سنجد؛ نه TLS Handshake و نه لحظه‌ی Established کامل (ACK نهایی) را. اگر هیچ Handshake کاملی در فایل نباشد → null.
zero_window_count قطعی بسته‌های TCP با window == 0، به‌استثنای SYN (که Window اولیه هنوز معنا ندارد) و RST (که فیلد Window در آن بی‌معناست).
tcp_reset_count قطعی شمارش مستقیم بسته‌های دارای پرچم RST.
retransmission_count Heuristic (صریحاً مستندشده) به ازای هر جهت جریان، map بازه‌های sequence پوشش‌داده‌شده نگه داشته می‌شود. بسته‌ای که بایته‌ایش قبلاً پوشش داده شده و peer هنوز ACK نکرده، Retransmission شمرده می‌شود. SYN/FIN تکراری هم شمرده می‌شوند. Out-of-order و Spurious جدا گزارش می‌شوند تا سیگنال بازیابی از دست‌رفتگی باد نکند.
out_of_order_count Heuristic سگمنت payloadدار که فقط بایت‌های جدید می‌آورد ولی از جلوی frontier پیوسته جلوتر شروع می‌شود (حفرهٔ sequence باقی می‌گذارد) — به‌جای retransmission اینجا شمرده می‌شود.
spurious_retransmission_count Heuristic سگمنت کاملاً پوشش‌داده‌شده‌ای که peer قبلاً تا انتهای آن را ACK کرده. از retransmission_count جداست تا resendهای غیرضروری، سیگنال loss-recovery را متورم نکنند.

گروه ۲ — کارایی مصرف داده (کل ترافیک IP)

شاخصنوعتعریف دقیق
bytes_transferred_total قطعی، با تصمیم طراحی مهم مجموع فیلد ip.len (نه طول فریم Pcap)، چون PCAPdroid با «PCAPdroid extensions» یک هدر Ethernet جعلی + Trailer ۲۸ بایتی اضافه می‌کند؛ جمع بر مبنای ip.len این Overhead مصنوعی را حذف و بین دو حالت DLT سازگار می‌کند.
bytes_payload_total قطعی TCP: ip.len − ip_hdr_len − tcp_hdr_len (با احتساب Options)؛ UDP: udp.ulen − 8؛ سایر: صفر.
overhead_ratio مشتق (total − payload) / total، با محافظت در برابر تقسیم بر صفر (فایل خالی → 0.0). در دامنه به‌صورت property محاسبه می‌شود تا هرگز با دو عدد حجمی تناقض نداشته باشد؛ روی سیم برای گزارش‌گیری materialize می‌شود.
تفسیر اعداد: اپ‌های پیام‌رسان مدرن اغلب bulk transfer را روی QUIC (UDP) می‌برند. بنابراین دیدن حجم بالا کنار Retransmission نزدیک صفر کاملاً طبیعی است. برای تمرین متریک‌های TCP، در تنظیمات اپ در صورت امکان QUIC را خاموش کنید.

۵ داستان یک باگ واقعی: چرا Oracle Test ارزشش را ثابت کرد

پیاده‌سازی اولیه‌ی RTT Handshake، هنگام گم‌شدن و بازارسال یک SYN، زمان را از روی آخرین تلاش موفق حساب می‌کرد (نتیجه: ۲۰ میلی‌ثانیه‌ی گمراه‌کننده به‌جای واقعیت). تست Oracle، با مقایسه‌ی مستقیم خروجی در برابر فیلد tcp.analysis.ack_rtt در Wireshark روی همان فایل، این ناهم‌خوانی را آشکار کرد: Wireshark مقدار ۳۰۲۰ میلی‌ثانیه گزارش می‌داد — دقیقاً بازه‌ی واقعی که اتصال طول کشیده بود. اصلاح شد تا از اولین SYN حساب شود، همان‌طور که هدف متریک (تشخیص افت اتصال) اقتضا می‌کند.

sequenceDiagram participant Client participant Server Client->>Server: SYN (t=0) — گم می‌شود Note over Client,Server: بازه‌ی سکوت ۳ ثانیه‌ای Client->>Server: SYN بازارسال‌شده (t=3000ms) Server-->>Client: SYN-ACK (t=3020ms) Note over Client: کد اشتباه: 3020-3000=20ms
کد درست (و Wireshark): 3020-0=3020ms
درس معماری: Unit test با Ground Truth مصنوعی باگ منطقی «آخرین SYN» را می‌دید اگر سناریوی retransmission SYN را تزریق می‌کرد — و کرد. Oracle ارزش اضافه‌اش این بود که تعریف متریک را با استاندارد صنعتی هم‌راستا کرد و جلوی «درست بودن نسبت به تست خودمان، غلط بودن نسبت به Wireshark» را گرفت.

۶ فلوی کامل یک اجرا

اسکریپت بچ هر فایل inbox را به main.py می‌سپارد؛ سرویس Composition‌شده مسیر validate → analyze → publish را طی می‌کند.

sequenceDiagram participant Script as scripts/analyze_pcaps.sh participant Main as main.py participant FP as filename_parser participant ARC as AppRegistryClient participant PR as packet_reader participant TCP as tcp_analyzer participant VOL as volume_analyzer participant MC as metrics_calculator participant MM as message_mapper participant KP as kafka_publisher Script->>Main: برای هر فایل در inbox/ Main->>FP: استخراج package_name و scenario از نام فایل Main->>ARC: اعتبارسنجی (وجود، is_active، is_messaging_app) alt نامعتبر ARC-->>Main: رد شود (خطای پیکربندی، بدون Retry) Main->>Script: انتقال فایل به failed/ + لاگ خطا else معتبر Main->>PR: خواندن پکت به پکت (DLT dispatch + strip Trailer) PR->>TCP: هر پکت TCP PR->>VOL: هر پکت IP TCP->>MC: شاخص‌های TCP VOL->>MC: ۲ شاخص حجمی MC->>MM: NetworkMetrics کامل MM->>KP: پیام JSON (snake_case + analysis_id + analyzed_at) KP->>Script: موفقیت Script->>Script: انتقال فایل به processed/ end
VALIDATE

اعتبارسنجی قبل از تحلیل

App API چک می‌کند اپ وجود دارد، فعال است، و is_messaging_app است. نام پکیج غلط در چند ثانیه روی ترمینال می‌میرد، نه هفته‌ها بعد در لاگ Consumer.

مکانیزم: AppRegistryClient + فلگ --skip-registry-check برای کار آفلاین
PUBLISH

انتشار، نه ماندگارسازی

Analyzer هرگز به Postgres وصل نمی‌شود. سند صراحتاً ماندگاری را به Storage واگذار کرده؛ یک کامپوننت مالک اعتبارنامه و migration می‌ماند.

مکانیزم: تاپیک network-metrics، کلید = package_name

۷ قرارداد داده و تصمیمات کلیدی سیم

این بخش اینترفیسی است که Storage Consumer روی آن پیاده‌سازی می‌کند. سبک پیام با Crawler یکی است: کلید پکیج، مقدار JSON تخت و snake_case، بدون envelope از نوع {type, payload}.

{ "analysis_id": "8f14e45f-ea6a-4f2b-9c1d-2b3a5c7d9e01", "package_name": "com.whatsapp", "scenario": "UPLOAD", "rtt_handshake": 43.12, "retransmission_count": 7, "out_of_order_count": 1, "spurious_retransmission_count": 0, "zero_window_count": 0, "tcp_reset_count": 2, "bytes_transferred_total": 18234123, "bytes_payload_total": 17540221, "overhead_ratio": 0.038, "source_pcap_filename": "com.whatsapp__upload__20260907T141500.pcap", "analyzed_at": "2026-09-07T14:20:11+00:00" }
فیلدیادداشت
analysis_idUUID4 یکتا به‌ازای هر تحلیل — کلید Idempotency برای ON CONFLICT DO NOTHING در Consumer. Kafka At-Least-Once است؛ بدون این فیلد، Replay فایل ردیف تکراری می‌ساخت و نمودارهای روند را خراب می‌کرد.
analyzed_atدر سمت Analyzer ثبت می‌شود، نه auto_now_add در دیتابیس — معنای «چه زمانی تحلیل واقعاً اجرا شد» را حفظ می‌کند، نه «چه زمانی Consumer پیام را خواند» (همان اصل crawled_at در Crawler).
package_nameهرگز application_id ارسال نمی‌شود؛ resolve کلید خارجی مال مالکی اسکیما است.
scenarioفقط UPLOAD یا DOWNLOAD.
rtt_handshakefloat یا JSON null؛ تا ۳ رقم اعشار.
فیلدهای داخلی CLIpacket_count و handshake_sample_count فقط برای گزارش stdout هستند و عمداً روی سیم نمی‌آیند تا Consumer به ستونی که در DB نیست وابسته نشود.

۸ فرمت‌های ضبط PCAPdroid و انتخاب ip.len

PCAPdroid فایل را در یکی از دو شکل می‌نویسد. Reader با dispatch روی link-type هدر فایل هر دو را پشتیبانی می‌کند:

Link typeچه موقعرفتار Reader
101 (raw IP)پیش‌فرض، از جمله root modeرکورد از هدر IP شروع می‌شود.
1 (Ethernet)فعال بودن «PCAPdroid extensions»هدر Ethernet جعلی + trailer حاوی UID و نام پکیج؛ trailer قبل از Parse IP جدا می‌شود.
جزئیات ظریف dpkt: مقایسه با اعداد literal انجام می‌شود نه ثابت‌های DLT_* کتابخانه، چون Reader.datalink() مقدار هدر فایل را برمی‌گرداند در حالی که dpkt.pcap.DLT_RAW ثابت سبک BSD پلتفرم است (12، نه 101).

جمع بر مبنای ip.len حدود ۴۶ بایت bookkeeping مصنوعی به‌ازای هر پکت (هدر جعلی + padding + trailer + checksum) را حذف می‌کند، بین دو حالت DLT یکسان می‌ماند، و نسبت به truncation ناشی از snaplen مقاوم‌تر است.

۹ Exit Codeها و مسیریابی بچ

اسکریپت analyze_pcaps.sh بر اساس کد خروج Analyzer تصمیم می‌گیرد فایل کجا برود. شکاف بین کد ۵ و بقیه حیاتی است: بروکر قطع‌شده نباید Capture سالم را قرنطینه کند، و فایل معیوب نباید تا ابد Retry شود.

کدمعنارفتار اسکریپت بچ
0تحلیل و انتشار موفقانتقال به processed/
1خطای پیکربندی یا غیرمنتظرهانتقال به failed/ + فایل .log
2خطای usage آرگومان (argparse)انتقال به failed/ + لاگ
3نام فایل بد یا اپ غیرمجازانتقال به failed/ + لاگ
4Capture خوانا نیستانتقال به failed/ + لاگ
5Kafka یا App API در دسترس نیستفایل در inbox می‌ماند برای تلاش مجدد

۱۰ نحوهٔ اجرا (Host، اسکریپت، Docker)

این زیرسیستم یک Job دسته‌ای on-demand است، نه Daemon. پشت پروفایل Compose به نام tools است تا docker compose up معمولی آن را بالا نیاورد.

۱۰.۱ تحلیل تک‌فایل روی Host

python -m venv .venv-analyzer .venv-analyzer/bin/pip install -r network_analyzer/requirements.txt cp network_analyzer/.env.example network_analyzer/.env # نام فایل کافی است python -m network_analyzer.main --file data/pcap/inbox/com.whatsapp__upload__20260907T141500.pcap # override برای فایلی که نمی‌توان تغییر نام داد python -m network_analyzer.main --file capture.pcap --package com.whatsapp --scenario UPLOAD # کاملاً آفلاین: بدون broker، بدون App API، بدون .env python -m network_analyzer.main --file capture.pcap --dry-run --skip-registry-check

۱۰.۲ بچ روی Host

./scripts/network/analyze_pcaps.sh ./scripts/network/analyze_pcaps.sh --dry-run --skip-registry-check --keep ./scripts/network/analyze_pcaps.sh --inbox ~/Downloads/PCAPdroid

۱۰.۳ Docker — الگوی Dispatcher

docker-entrypoint.sh بر اساس آرگومان اول بین بچ کل inbox/ (پیش‌فرض / --batch) و تحلیل تک‌فایل (--file …) سوییچ می‌کند — همان الگوی Imageهای رسمی Postgres برای یک Image با چند حالت استفاده، بدون نیاز به دو Image جدا.

docker compose --profile tools build network-analyzer # پیش‌فرض: بچ روی /data/pcap/inbox docker compose --profile tools run --rm network-analyzer # بچ با فلگ docker compose --profile tools run --rm network-analyzer --batch --dry-run --keep # تک‌فایل (مسیر داخل کانتینر) docker compose --profile tools run --rm network-analyzer \ --file /data/pcap/inbox/com.whatsapp__upload__20260907T141500.pcap
تفکیک env: فایل network_analyzer/.env برای Host است (localhost:9092). کانتینر از docker-compose.yml مقادیر شبکهٔ داخلی می‌گیرد (kafka:29092، http://app-api:8000). پوشهٔ ./data/pcap به /data/pcap bind می‌شود.

۱۱ استراتژی تست سه‌لایه

flowchart TD A["Unit Tests
Synthetic PCAP با scapy.wrpcap
Ground Truth دقیق"] --> B["Oracle Tests
مقایسه با tshark
marker: oracle"] B --> C["Live Tests
App API و Kafka واقعی
marker: live"] C --> D["End-to-End دستی
Capture واقعی PCAPdroid
تا مشاهده در Kafka UI"] style A fill:#16a34a,color:#fff style B fill:#f59e0b,color:#fff style C fill:#dc2626,color:#fff style D fill:#7c3aed,color:#fff
لایهچه چیزی را تضمین می‌کند
Unit (Synthetic)منطق داخلی با Ground Truth کنترل‌شده مطابقت دارد؛ سریع، قطعی، بدون فایل باینری Commit‌شده. تعداد دقیق retransmission / zero-window / RST تزریق و assert می‌شود.
Contractmessage_mapper شکل JSON سیم را بدون نیاز به broker ثابت نگه می‌دارد.
Oracle (tshark)خروجی با ابزار مستقل صنعتی هم‌خوان است؛ همین لایه باگ واقعی RTT را کشف کرد. بدون tshark به‌صورت خودکار skip می‌شود.
Liveفرض‌های Mock دربارهٔ App API و Kafka در دنیای واقعی هم برقرارند.
End-to-End دستیکل زنجیره (ضبط واقعی → تحلیل → Kafka → در نهایت Storage) با هم کار می‌کند.

۱۱.۱ اجرا روی Host

# سریع — پیش‌فرض CI محلی python -m pytest network_analyzer/tests/ -q -m "not live and not oracle" # Oracle — نیاز به tshark python -m pytest network_analyzer/tests/ -q -m oracle # Live — نیاز به Kafka و App API روشن python -m pytest network_analyzer/tests/ -q -m live

۱۱.۲ اجرا در Docker (پروفایل test)

سرویس ComposeمحتواImage
network-analyzer-testsUnit + Contract (not live and not oracle)Dockerfile معمولی
network-analyzer-tests-liveمارکر live روی شبکهٔ Composeهمان Image
network-analyzer-tests-oracleمارکر oracleDockerfile.test با tshark
docker compose --profile test run --rm network-analyzer-tests docker compose --profile test run --rm network-analyzer-tests-live docker compose --profile test run --rm network-analyzer-tests-oracle # یا ارکستراتور کلی پروژه ./scripts/run_tests_in_docker.sh

۱۲ اسکریپت‌ها و نقاط اتصال مرتبط

مسیرارتباط با Network Analyzer
scripts/network/analyze_pcaps.sh بچ روی inbox؛ مسیریابی فایل بر اساس exit code.
scripts/verify/verify_network_metrics.sh تأیید انتشار روی تاپیک (قبل/مکمل persist در Storage).
scripts/run_tests_in_docker.sh صف تست‌های unit / live / oracle این زیرسیستم.
Storage Consumer مصرف‌کنندهٔ تاپیک network-metrics و مالک جدول هم‌نام.
Database Schema ستون‌های جدول network_metrics و قید Idempotency روی analysis_id.

۱۳ تصمیمات کلیدی معماری

انتشار به Kafka، نه نوشتن مستقیم در Postgres

سند صراحتاً ماندگاری دادهٔ شبکه را به زیرسیستم Storage واگذار کرده. نگه‌داشتن اعتبارنامه‌ی دیتابیس فقط در یک کامپوننت، دو سرویس مستقل را به یک اسکیمای فیزیکی مشترک وابسته نمی‌کند. پیامد جانبی: لاگ Kafka خودش آرشیو نتایج است؛ باگ mapping در Consumer با reset offset درست می‌شود، نه با ضبط دوباره روی گوشی.

هسته‌ی خالص analysis/

بدون Kafka/HTTP/Config در هسته، Milestoneهای M1–M3 و صدها تست Synthetic بدون زیرساخت ممکن شد و سرعت بازخورد توسعه حفظ شد.

افزودن analysis_id (UUID یکتا)

Kafka At-Least-Once است. UUID به‌ازای هر تحلیل، ON CONFLICT DO NOTHING را در Consumer ممکن می‌کند بدون از بین بردن intent append-only: اجرای مجدد واقعی تست، UUID جدید و ردیف جدید می‌سازد.

analyzed_at در Analyzer، نه DB

معنای زمانی تحلیل باید مستقل از زمان خواندن پیام توسط Consumer بماند — هم‌راستا با crawled_at در Crawler.

جداسازی messaging/ از clients/

دو I/O با الگوی خطای متفاوت (broker در برابر REST) عمداً در دو پوشه ماندند تا مرز مسئولیت شفاف بماند.

جمع حجم روی ip.len نه طول فریم

حذف overhead مصنوعی PCAPdroid extensions و سازگاری بین DLT خام و Ethernet.

RTT از اولین SYN؛ تفکیک OOO و Spurious از Retransmission

متریک باید افت اتصال را نشان دهد، نه فقط RTT تلاش موفق. Heuristic retransmission با interval map و peer ACK، سیگنال‌های متفاوت را قاطی نمی‌کند.

Entrypoint Dispatcher برای Docker

یک Image، دو حالت (بچ / تک‌فایل) — الگوی رسمی Postgres — بدون دو Dockerfile موازی.

Exit code ۵ برای خطای حمل‌ونقل

فایل سالم روی قطعی موقت زیرساخت قرنطینه نمی‌شود؛ فقط ورودی‌های غیرقابل‌قبول به failed/ می‌روند.

تکرار عامدانه‌ی retry_policy

مثل Crawler و Storage Consumer: هر زیرسیستم واحد استقرار مستقل است و سورس بقیه در Imageش نیست. مجموعه‌ی خطاهای قابل Retry مخصوص HTTP/Kafka این سرویس است.

۱۴ ابزارها و تکنولوژی‌های استفاده‌شده

ابزارنقش
dpktخواندن و Parse کردن فایل‌های PCAP در سطح بایت
tshark (Wireshark CLI)Oracle مستقل برای اعتبارسنجی دقت متریک‌ها؛ فقط وابستگی توسعه، نه Production
scapyساخت Synthetic PCAP با Ground Truth دقیق برای تست‌های واحد
kafka-pythonانتشار پیام به Topic network-metrics
requestsاعتبارسنجی اپلیکیشن از طریق App API قبل از تحلیل
PCAPdroidابزار ضبط ترافیک روی گوشی اندروید (منبع ورودی)
pytest (+ markers)Unit / Contract / Oracle / Live با جداسازی پیش‌نیازها
Docker Compose profiles tools / testJob on-demand و کانتینرهای تست بدون قاطی شدن با استک پیش‌فرض
python-dotenvبارگذاری network_analyzer/.env در اجرای Host