পাঠ ০৮ · ৫৭-এর মধ্যে · মডিউল ৩
Home / Courses / Computer Networks / ফ্রেমিং

ফ্রেমিং ও ডেটা লিংক লেয়ার বেসিকস

Framing & data link layer basics
৮ মিনিট পড়া প্রাথমিক · Beginner Python কোডসহ সম্পূর্ণ বাংলায়

এই পাঠে যা শিখবেন

  • ডেটা লিংক লেয়ারের মূল কাজ — কেন "ফ্রেমিং" ছাড়া রিসিভার বুঝতেই পারবে না ডেটা কোথায় শুরু-শেষ হচ্ছে
  • তিনটি প্রধান ফ্রেমিং পদ্ধতি — বাইট স্টাফিং, বিট স্টাফিং, লেংথ-বেসড
  • Python-এ একটি বাস্তব বাইট-স্টাফিং stuff/unstuff ইমপ্লিমেন্টেশন
  • কীভাবে ESCAPE বাইট নিশ্চিত করে যে ডেটার ভেতরের FLAG-এর মতো বাইটও ভুলভাবে সীমানা হিসেবে ধরা পড়ে না

১ · ডেটা লিংক লেয়ারের কাজ — ফ্রেমিং

M2 (ফিজিক্যাল লেয়ার, L05-07) শুধু একটি টানা বিট-স্ট্রিম পাঠাতে ও গ্রহণ করতে জানে — এটি জানে না কোথায় একটি বার্তা শেষ হচ্ছে আর পরেরটি শুরু হচ্ছে। ডেটা লিংক লেয়ারData Link LayerOSI মডেলের দ্বিতীয় স্তর — ফিজিক্যাল লেয়ারের কাঁচা বিট-স্ট্রিমকে স্বতন্ত্র ফ্রেমে সংগঠিত করে, এরর ডিটেকশন/কারেকশন (M3/L09-10) ও MAC অ্যাড্রেসিং (M3/L11) পরিচালনা করে। এই সমস্যা সমাধান করে — কাঁচা বিটগুলোকে স্পষ্ট শুরু ও শেষ-সহ স্বতন্ত্র ফ্রেমে সংগঠিত করে।

কেন এটি একটি বাস্তব সমস্যা

কল্পনা করুন একটি তারে শুধু 0 আর 1-এর একটি অবিরাম স্রোত আসছে — কোনো কমা, কোনো স্পেস নেই। রিসিভার কীভাবে জানবে প্রথম ১০০ বিট একটি বার্তা, নাকি প্রথম ৫০ বিট একটি বার্তা আর পরের ৫০ বিট আরেকটি? ফ্রেমিং ছাড়া এই প্রশ্নের কোনো উত্তর নেই — এটিই ডেটা লিংক লেয়ারের সবচেয়ে মৌলিক দায়িত্ব।

২ · ফ্রেম সীমানা নির্ধারণের পদ্ধতি

বাইট/ক্যারেক্টার স্টাফিং
একটি বিশেষ FLAG বাইট ফ্রেমের শুরু ও শেষ চিহ্নিত করে; ডেটার ভেতর সেই বাইটের মান এলে একটি ESCAPE বাইট আগে বসিয়ে দেওয়া হয়, যাতে রিসিভার প্রকৃত ডেটাকে ভুলভাবে সীমানা হিসেবে না ধরে।
বিট স্টাফিং
একই ধারণা কিন্তু বিট পর্যায়ে (যেমন 01111110-এর মতো একটি নির্দিষ্ট বিট-প্যাটার্ন সীমানা হিসেবে ব্যবহার করে, HDLC প্রোটোকলে ব্যবহৃত)।
লেংথ-বেসড ফ্রেমিং
ফ্রেমের হেডারেই নিজের মোট দৈর্ঘ্য লেখা থাকে — রিসিভার আগে থেকেই জানে ঠিক কত বাইট পড়ে থামতে হবে।

৩ · বাইট স্টাফিং বিস্তারিত

বাইট স্টাফিং-এ একটি নির্দিষ্ট বাইট মান (প্রায়ই 0x7E, বাইনারিতে 01111110) ফ্রেমের শুরু ও শেষে বসানো হয় — একে FLAG বলে। সমস্যা হলো: আসল ডেটার ভেতরেই যদি এই একই বাইট মান থেকে থাকে (সম্পূর্ণ স্বাভাবিক, ডেটা তো যেকোনো বাইনারি হতে পারে), তাহলে রিসিভার ভুলভাবে সেটিকে ফ্রেমের সমাপ্তি ভেবে ফেলতে পারে। সমাধান — একটি ESCAPE বাইট (0x7D) FLAG-এর মান বা ESCAPE নিজের মান পাওয়া গেলে তার ঠিক আগে বসিয়ে দেওয়া, যাতে রিসিভার বুঝতে পারে "পরের বাইটটি আসল ডেটা, সীমানা নয়।"

Python
# বাইট স্টাফিং / আনস্টাফিং -- ফ্রেম সীমানা নিরাপদে চিহ্নিত করা
FLAG = 0x7E     # ফ্রেমের শুরু/শেষ চিহ্নিতকারী বাইট
ESCAPE = 0x7D   # FLAG বা ESCAPE-এর প্রকৃত ডেটা মান লুকানোর জন্য

def stuff(data_bytes, flag=FLAG, escape=ESCAPE):
    """ডেটার ভেতর FLAG/ESCAPE-এর মান পেলে তার আগে ESCAPE বসিয়ে দেয়,
    তারপর পুরো ফ্রেমটিকে FLAG দিয়ে মুড়ে দেয়।"""
    out = bytearray()
    for b in data_bytes:
        if b == flag or b == escape:
            out.append(escape)
        out.append(b)
    return bytes([flag]) + bytes(out) + bytes([flag])

def unstuff(stuffed_bytes, flag=FLAG, escape=ESCAPE):
    """stuff()-এর বিপরীত -- বাইরের FLAG সরিয়ে, প্রতিটি ESCAPE বাইট
    সরিয়ে তার ঠিক পরের বাইটকে আসল ডেটা হিসেবে রাখে।"""
    assert stuffed_bytes[0] == flag and stuffed_bytes[-1] == flag
    inner = stuffed_bytes[1:-1]
    out = bytearray()
    i = 0
    while i < len(inner):
        if inner[i] == escape:
            i += 1  # পরের বাইটটিই আসল ডেটা, ESCAPE নিজে বাদ
        out.append(inner[i])
        i += 1
    return bytes(out)

# ডেটাতে ইচ্ছাকৃতভাবে FLAG (0x7E) ও ESCAPE (0x7D) মানই রাখা হলো
original = bytes([0x48, 0x65, 0x7E, 0x6C, 0x7D, 0x6C, 0x6F])
print("মূল ডেটা (হেক্স):     ", original.hex(' '))

framed = stuff(original)
print("স্টাফড ফ্রেম (হেক্স):  ", framed.hex(' '))

recovered = unstuff(framed)
print("আনস্টাফড ডেটা (হেক্স):", recovered.hex(' '))

print("\nমূল ডেটার সাথে হুবহু মিলছে?", recovered == original)

    
FLAG ডেটা … [ESCAPE + FLAG-এর মান] … ডেটা FLAG ← স্টাফড ফ্রেম: বাইরের FLAG সীমানা, ভেতরের আসল FLAG মান ESCAPE দিয়ে সুরক্ষিত →
ফ্রেমের বাইরের দুই প্রান্তেই FLAG বাইট বসে, আর ভেতরে যদি আসল ডেটাতেই FLAG-এর মান থেকে থাকে, তার আগে একটি ESCAPE বাইট বসানো হয় যাতে বিভ্রান্তি না হয়।
লক্ষ্য করুন — উপরের উদাহরণে ডেটাতে ইচ্ছাকৃতভাবে 0x7E (FLAG-এর মান) ও 0x7D (ESCAPE-এর মান) দুটোই রাখা হয়েছে, তারপরও স্টাফ-করে-আনস্টাফ করলে মূল ডেটা হুবহু ফিরে এসেছে। এটিই বাইট স্টাফিং-এর মূল গ্যারান্টি — ডেটার প্রকৃত বিটপ্যাটার্ন যাই হোক না কেন, ফ্রেমের সীমানা কখনো বিভ্রান্ত হয় না।
মূল কথা · Key takeaway

ফ্রেমিং হলো নেটওয়ার্কিং-এর সবচেয়ে মৌলিক "যতিচিহ্ন বসানোর" সমস্যা — একটি অবিরাম বিট-স্ট্রিমকে অর্থপূর্ণ, স্বতন্ত্র একক-এ ভাগ করা। M3-এর বাকি পাঠগুলো (L09-13) ধরেই নেয় যে আমরা ইতিমধ্যে একটি সম্পূর্ণ ফ্রেম হাতে পেয়েছি — এখন প্রশ্ন হলো সেই ফ্রেমে কোনো এরর আছে কিনা (L09-10), আর কাকে পাঠানো হচ্ছে (L11-13)।

ভাবনার প্রশ্ন

প্রতিটি প্রশ্ন নিজে কিছুক্ষণ ভাবুন — তারপর "→ উত্তর" চাপুন।

প্র ০১ লেংথ-বেসড ফ্রেমিং-এর একটি বাস্তব দুর্বলতা কী হতে পারে, যা বাইট স্টাফিং-এ নেই?

লেংথ-বেসড ফ্রেমিং-এ যদি লেংথ ফিল্ডটি নিজেই ট্রান্সমিশনে করাপ্ট হয়ে যায় (একটি বিট ফ্লিপ হয়), রিসিভার ভুল সংখ্যক বাইট পড়বে — যা পরবর্তী ফ্রেমের শুরুতেই বিভ্রান্তি তৈরি করবে, কারণ রিসিভার এখন "ভুল জায়গায়" পরবর্তী ফ্রেমের হেডার খুঁজবে। বাইট স্টাফিং-এ FLAG বাইট নিজেই একটি সুস্পষ্ট, পুনরাবৃত্তিমূলক সীমানা মার্কার হওয়ায় একটি ফ্রেম করাপ্ট হলেও পরের FLAG থেকে রিসিভার সহজেই পুনরায় সিঙ্ক্রোনাইজ করতে পারে।

প্র ০২ ESCAPE বাইট নিজেই যদি ডেটাতে থাকে (FLAG নয়), তাহলে কী হয় — এটিও কি স্টাফ করা দরকার?

হ্যাঁ — উপরের কোডে লক্ষ্য করুন stuff() ফাংশনটি FLAG এবং ESCAPE উভয়ের মানের জন্যই স্টাফিং করে। যদি শুধু FLAG স্টাফ করা হতো আর ESCAPE-এর প্রকৃত মান ডেটাতে অস্টাফড রেখে দেওয়া হতো, তাহলে unstuff() ভুলভাবে সেই ডেটা বাইটকে একটি "escape sequence"-এর শুরু ভেবে পরের বাইটটিকে ভুলভাবে ব্যাখ্যা করে ফেলত — তাই ESCAPE বাইটকেও নিজের মানের জন্য স্টাফ করতে হয়, নাহলে পুরো স্কিমটি ভেঙে পড়ে।

প্র ০৩ বিট স্টাফিং (HDLC-এর) বাইট স্টাফিং-এর চেয়ে কোন পরিস্থিতিতে সুবিধাজনক হতে পারে?

বিট স্টাফিং কাজ করে বিটের একটি নির্দিষ্ট প্যাটার্নের (যেমন 01111110) উপর, বাইট-সীমানার (৮-বিট গ্রুপিং) উপর নির্ভরশীল নয় — তাই এটি এমন লিংকেও কাজ করে যেখানে ডেটা বাইট-অ্যালাইনড নয় (bit-oriented protocols, বিভিন্ন লেংথের ফিল্ড থাকতে পারে)। বাইট স্টাফিং ধরে নেয় ডেটা সবসময় ৮-বিট বাইটে সংগঠিত, যা সব লিংক-লেয়ার প্রযুক্তির জন্য সত্য নয়।

অনুশীলন

  1. পরীক্ষা করুন: উপরের কোড সেলে original-এ এমন একটি বাইট-স্ট্রিং বসান যাতে দুইটি পরপর 0x7E (FLAG) মান থাকে — নিশ্চিত করুন stuff-then-unstuff তারপরও মূল ডেটা হুবহু ফিরিয়ে দেয়।

    হ্যাঁ, কাজ করবে — stuff() ফাংশনটি প্রতিটি পৃথক FLAG-মানের বাইটের আগে আলাদাভাবে ESCAPE বসায় (লুপে প্রতিটি বাইট আলাদা করে পরীক্ষা করে), তাই পরপর দুটি FLAG-মান থাকলেও প্রতিটির আগে নিজস্ব ESCAPE বসবে এবং unstuff() দুটোই সঠিকভাবে পুনরুদ্ধার করবে।

  2. চিন্তা করুন: যদি ট্রান্সমিশনের সময় একটি ESCAPE বাইট নিজেই হারিয়ে যায় (drop হয়ে যায়, কিন্তু বিট-এরর নয়), তাহলে unstuff()-এর ফলাফলে কী সমস্যা হতে পারে?

    ESCAPE বাইট হারিয়ে গেলে তার পরের বাইটটি (যেটি আসলে একটি প্রকৃত FLAG বা ESCAPE মান ছিল) এখন সরাসরি রিসিভারের কাছে "সীমানা মার্কার" হিসেবে ধরা পড়বে — ফ্রেমটি ভুল জায়গায় ভেঙে যাবে বা অসম্পূর্ণ পড়া হবে। এই কারণেই ফ্রেমিং শুধু বিটপ্যাটার্ন সঠিক রাখাই যথেষ্ট নয় — L09-এর এরর ডিটেকশন (CRC) নিশ্চিত করে যে এমন করাপশন ধরা পড়ে, যাতে করাপ্ট ফ্রেম বাতিল করে পুনরায় পাঠানো যায়।

আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ

আগের পাঠ
মাল্টিপ্লেক্সিং — FDM, TDM, WDM