Xem mẫu

  1. CHƢƠNG 7. QUẢN LÝ VÙNG ĐỆM VÀ ĐƢỜNG LIÊN KẾT Mục tiêu Liên kết (Link) là một đối tƣợng OTcl kết nối giữa hai nút để truyền các gói tin từ nút bắt đầu nguồn nút đích. Nội dung của chƣơng này chủ yếu tập trung vào lớp có tên là SimpleLink là Lớp đƣợc sử dụng rộng rãi nhất trong số các lớp thừa kế từ Lớp Link. Đối tƣợng SimpleLink mô hình hóa thời gian truyềứ gói tin, độ trễ của kênh truyền và bộ đệm gói tin để truyền các gói tin từ một nút này tới một nút khác, ở đây, thời gian truyền gói tin là thời gian cần thiết đề thiết bị truyền gửi đi một gói tin. Nó đƣợc xác định bởi băng thông của kênh truyền và kích cỡ gói tin. Thời gian trễ của kênh truyền là thời gian cần thiết để mang mỗi bit từ điểm đầu tới điểm cuối trên kênh truyền. Một thiết bị truyền có thể nhận đƣợc các gói tin trong khi nó đang truyền các gói tin khác. Các gói tin đi đến một thiết bị truyền đang bận có thể đƣợc đƣa vào một bộ đệm để truvền đi ở thời điểm sau. Không giống nhƣ trong thực tế, NS2 triển khai việc đệm gói tin trong một kênh truyền chứ không phải trong một nút. 7.1. Giới thiệu về đối tƣợng SimpleLink NS2 mô hình hóa một kênh truyền bằng các sử dụng các Lớp đƣợc dẫn xuất từ Lớp Link của OTcl. Trong số các Lớp này, Lớp SimpleLink là lớp đơn giản nhất có thể đƣợc sử dụng để kết nối giữa hai nút.  Các thành phần chính của một Lớp SimpleLink Hình 7.1 đƣa ra một hình ảnh kết hợp giữa các thành phần của Lớp SimpleLink với các đối tƣợng cơ bản và các đối tƣợng lƣu vết trong cây thông dịch nhƣ sau: Hình 7.1. Kiến trúc của một đối tƣợng SỉmpỉeLink Các đối tƣợng cơ bản head_: Điểm truy cập của đối tƣợng SỉmpleLink queue_: Là một đối tƣợng Queue, nó thực hiện mô hình hóa bộ đệm gói tin của một router thực (xem Mục 7.3). link_: Là đối tƣợng DelayLỉnk, thực hiện mô hình hóa thời gian truvền gói tin và thời gian trễ của kênh truyền (xem Mục 7.2) ttl_: Là một đối tƣợng kiểm tra thời gian sống (time to live) của lớp TTLChecker. Khi một gói tin tới, đối tƣợng này thực hiện việc giảm giá trị TTL của gói tin. Sau đó nó kiểm tra nếu giá trị TTL của gói tin vẫn là giá trị dƣơng, gói tin sẽ - 131 -
  2. đƣợc chuyển tiếp tới thành phần tiếp theo trên kênh truyền. Ngƣợc lại, nó sẽ hủy gói tin ra khỏi quá trình mô phỏng (xem file "ns/common/ttl.h.cc). đropheacL: Là điểm hủy gói tin của kênh truyền. Các gói tin bị hủy sẽ đƣợc chuyển tiếp tới đối tƣợng này. Nó thƣờng đƣợc kết nối với tác tử rỗng của đối tƣợng Simulator để mọi đối tƣợng SỉmpleLink có thể chia sẻ cùng một điểm hủy gói tin. Các đối tƣợng lƣu vết Các đối tƣợng này sẽ đƣợc chèn vào chỉ khi biến thành viên $traceAHFile_ đƣợc định nghĩa. Các đối tƣợng này bao gồm: enqT_: Lƣu vết các gói tin đi vào hàng đợi queue_ deqT_: Lƣu vết các gói tin đi ra từ hàng đợi queue_ drpT_: Lƣu vết các gói tin bị hủy từ hàng đợi queue_ rcvT_: Lƣu vết các gói tin đi ra khỏi kênh truyền hoặc đƣợc các nút tiếp theo nhận. 7.1.1. Các thủ tục instproc để cấu hình đối tƣợng SimpleLink Trong miền OTcl, một đối tƣợng SỉmpleLỉnk đƣợc tạo ra bằng cách sử dụng thủ tục instproc simplex-lỉnkL"} và duplex-lỉnkr---} của lớp Simulator với cú pháp nhƣ sau: Trong đó $ns là đối tƣợng Simulator và $nl, $n2 là các đối tƣợng Node. Thủ tục instproc simplex-Tink{”-} ở trên tạo một đối tƣợng SimpleLink kết nối 1 chiều giữa nút $nl với nút $n2 (Chƣong trình 7.1). Tốc độ và thời gian trễ của kênh truyền đƣợc đƣa vào tham số (tính theo đon vị bps) và (tính theo đon vị giây). Khác với router thực, NS2 tích hợp hàng đợi trong đối tƣợng SimpleLỉnk chứ không phải trong đối tƣợng Node. Kiểu của hàng đợi trong kênh truyền đƣợc chỉ định bởi tham số . - 132 -
  3. Chƣơng trình 7.1 đƣa ra chi tiết của thủ tục Simulator-simplex- link{"}. Dòng 6 tạo một đối tƣợng của lớp Queue/qtype. Dòng 12 khởi tạo một đối tƣợng SimpleLink kết nối giữa nút n1 và n2. Nó thiết lập độ trễ, băng thông và đối tƣợng Queue của kênh truyền tƣơng ứng là bw, delay và q. Đối tƣợng Simulator lƣu đối tƣợng SimpleLink đƣợc tạo ra vào mảng liên kết link_($sid:$did) của nó với sid là ID định danh của nút nguồn và did là ID định danh của nút đích (xem Chƣơng 4). Thủ tục duplex-link "-} tạo ra hai đối tƣợng SimpleLink. Một đối tƣợng kết nối từ nút $n1 tới nút $n2 và một đối tƣợng kết nối từ nút $n2 tới nút $n1. Bạn đọc có thể xem chi tiết của thủ tục này trong file ~ns/tcl/lib/ns-lib.tcl. 7.1.2. Khỏi tạo của Lớp SimpleLink Chƣơng trình 7.2 đƣa ra chi tiết của thủ tục init{ —} của lớp SỉmpleLỉnk để khởi tạo và kết nối các đối tƣợng theo Hình 7.1. Trong chƣơng trình này các dòng 3, 5, 11, 12 và 18 tạo ra các biến thành viên drophead_, head_ queue_ link_ và ttl_ là các đối tƣợng của các lớp OTcl tƣơng ứng là Connector Connector, Queue, DelayLink và TtlChecker. Chú ý rằng băng thông và độ trễ của biến link_ đƣợc cấu hình trong dòng 13-14 Ngoài việc tạo ra các đối tƣợng trên, thủ tục khởi tạo này còn kết nối các đối tƣợng đƣợc tạo ra nhƣ Hình 7.1. Đƣợc dẫn xuất từ lớp Connector, mỗi một đối tƣợng - 133 -
  4. đƣợc tạo ra sử dụng lệnh target và drop-target để thiết lập đối tƣợng nhận gói và đối tƣợng hủy gói (xem Chƣơng 5). Dòng 9 thiết lập đối tƣợng nhận của head_ là q. Dòng 15 thiết lập đối tƣợng nhận của queue_ là link_. Dòng 16 thiết lập đối tƣợng nhận của link_ là điểm truy cập của nút kế tiếp. Dòng 19 và 21 chèn biến ttl_ vào giữa lỉnk_ và điểm truy cập của nút kế tiếp. Dòng 17 thiết lập điểm hủy gói tin của queue_ là dropheacL. Cuối cùng, dòng 4 thiết lập đích của drophead_ là tác tử rỗng của đối tƣợng Simulator. 7.2. Mô hình truyền gói tin  Cơ chế truyền gói tín NS2 mô hình hóa cơ chế truyền gói tin bằng cách sử dụng lớp C++ LinkDelay (xem Chƣơng trinh 7.3). Lớp C++ này đƣợc liên kết với lớp DelayLink của OTcl. Lớp DelayLink đƣợc sử dụng để khởi tạo biến thành viên SimpleLink::Link_. Đây là biến dùng để mô hình hóa tiến trinh truyền gói tin. Một tiến trình truyền gói tin bao gồm thời gian truyền gói tin và thời gian trễ của kênh truyền. Khi một đối tƣợng LinkDelay nhận một gói tin, nó đƣa vào dòng thời gian mô phỏng hai sự kiện: - 134 -
  5.  Sự kiện truyền gói tin đi từ đối tượng truyền: Thời gian truyền gói tin đƣợc định nghĩa bằng (kích thƣớc gói tin / băng thông). Đây là thời gian cần thiết để truyền một gói tin qua một kênh truyền. Sau một chu kỳ của thời gian truyền gói tin, gói tin hoàn toàn đi ra khỏi thiết bị truyền và thiết bị truyền đƣợc phép tiếp tục truyền gói tin tiếp theo. Nhờ vào sự kiện nhận gói tin một đối tƣợng LinkDelay sẽ đợi một chu kỳ thời gian truyền gói tin và báo cho đối tƣợng gửi biết rằng nó đã sẵn sàng để nhận một gói tin tiếp theo.  Sự kiện nhận gói tin về tại đối tượng nhận: Thời gian trễ khi truyền gói tin đƣợc định nghĩa bằng thời gian cần thiết để truyền một bit từ điểm bắt đầu tới điểm kết thúc trên một kênh truyền. Nhƣ vậy, toàn bộ gói tin cần một khoảng thời gian bằng ―thời gian truyền + thời gian trễ‖ để đi tới đích. Do đó, đối tƣợng LinkDelay sẽ lập lịch cho sự kiện nhận gói tin tại nút nhận sau khoảng thời gian trên.  Lớp LinkDelay trong C++ Chƣơng trình 7.3 đƣa ra khai báo của Lớp C++ LinkDelay. Lớp này có bốn biến chính. Biến bandwidth_ (dòng 15) lƣu băng thông của kênh truyền. Biến delay_ (dòng 16) lƣu thời gian trễ khi truyền. Dòng 4 và 5 liên kết hai biến này với các biến có cùng tên trong OTcl. Lớp LỉnkDelay lƣu mọi gói tin sẽ đƣợc truyền trong bộ đệm itq_ của nó (dòng 17). Biến itq_ là một con trỏ trỏ tới đối tƣợng PacketQueue (xem Mục 7.3.1). Cuối cùng, biến ỉntr_là một đối tƣợng Event giả biểu diễn sự kiện gói tin rời khỏi nút truyền. Sự kiện này đƣơc lập lịch bằng cách sử dụng biến ỉntr_ mà không cần đến cơ chế thực thi sự kiện (xem Mục 4.3.6). Các hàm chính của Lớp LinkDelay là hàm recv(p,h), hàm send(p,h), hàm handle(e) và hàm txttime(p). Hàm txttỉme(p) tính thời gian truyền của gói tin *p (dòng 10-12 trong Chƣơng trình 7.3). Hàm send(p,h) gửi gói tin *p tới đối tƣợng nhận (dòng 12 trong Chƣơng trinh 7.3). Hàm handle(e) đƣợc gọi khi bộ lập lịch thực thi sự kiện tƣơng ứng với đối tƣợng LinkDelay (xem Chƣơng 4). Hàm recv(p.h) lập lịch cho các sự kiện gói tin rời khỏi nút truyền và gói tin tới nút nhận từ hai đối số đầu vào là gói tin *p và thẻ quản lý *h. - 135 -
  6.  Sự kiện gói tin rời khỏi nút truyền: Vì một gói tin cần ‗thời gian truyền‖ (biến txt trong dòng 3) tại đối tƣợng truyền nên hàm recv(p,h) sẽ lập lịch cho sự kiện gói tin rời khỏi nút truyền tại thời điểm txt giây sau khi đối tƣợng LỉnkDelay nhận đƣợc gói tin. Để thực hiện việc này, dòng 10 gọi hàm scheđule(h,Sántr,txt) của lớp Scỉieđuler với đối số thứ nhất là thẻ quản lý, đối số thứ hai là sự kiện giả và đối số thứ ba là thời gian trễ. Sau khoảng thời gian txt giây, bộ lập lịch thực thi sự kiện này bằng cách gọi hàm handle(e) liên kết với thẻ quản lý *h để báo cho đối tƣợng gửi biết sự kiện một gói tin đã rời đi. Trong hầu hết mọi trƣờng hợp, đối tƣợng gửi đáp ứng lại bằng cách truyền một gói tin tiếp theo nếu có (xem Mục 7.3.3 về cơ chế gọi ngƣợc).  Sự kiện gói tin đến: Lớp LinkDelay cũng thực hiện việc truyền gói tin tới đối tượng nhận (*target). Dòng 8 thực hiện việc lập lịch cho một sự kiện lấy từ gói tin đầu vào *p với thời gian trễ txt+đelay_ giây. Trong đó, txt là thời gian truyền và đelay_ là thời gian trễ trên kênh truyền. Ở đây, *target_ được truyền từ hàm schedule( - ) dưới dạng một con trỏ Handler. Sau khoảng thời gian “txt+delay_” giây, hàm h.handle(p) sẽ gọi hàm recv(p) (xem Chương trình 4.2) và gói tin *p sẽ được truyền tới đối tượng *target_ sau khoảng thời gian txt+delay_ giây. Sự khác biệt chính giữa việc lập lịch cho sự kiện gói tin rời đi từ nguồn và gói tin đến đích là nhƣ sau: Trong khi một nút chỉ có thể giữ một gói tin thì một kênh truyền có thể chứa nhiều hơn một gói tin. Vì thế, một đối tƣợng Link chỉ có thể lập lịch cho một sự kiện gói tin rời đi từ nguồn (sử dụng biến intr_) và nhiều hơn một sự kiện gói tin đến đích (sử dụng *p để biểu diễn một gói tin). Bất kỳ lúc nào đối tƣợng LinkDelay nhận đƣợc một gói tin, nó sẽ lập lịch cho sự kiện gói tin rời đi từ nguồn bằng cách sử dụng biến sự kiện giả ỉntr_. Nếu biến intr_ không thực thi đƣợc, bộ lập lịch sẽ gây ra lỗi trong thời gian chạy bởi vì nó cố đƣa một gói tin vào đầu bộ đệm mà bộ đệm này lại đang bị chiếm giữ bởi gói tin khác. Ngƣợc lại, đối với sự kiện gói tin đến đích, đối tƣợng LinkDelay lập lịch cho sự kiện gói tin tới nút đích cho mọi gói tin nó nhận đƣợc (xem dòng 8 trong Chƣơng trình 7.4). Do đó, một liên kết có thể lập lịch cho một sự kiện gói tin đến đích trong khi sự kiện gói tin tới đích trƣớc đó vẫn chƣa đƣợc thực thi. Đây là trƣờng hợp rất phổ biến đối với các kênh truyền có thời gian trễ lớn có thể chứa nhiều gói tin đồng thời. 7.3. Quản lý vùng đệm Một thành phần chính khác của đối tƣợng SimpleLink là lớp Queue. Lớp Queue mô hình hoá cơ chế bộ đệm trong router. Nó lƣu gói tin nhận đƣợc trong bộ đệm, chuyển tiếp lần lƣợt từng gói tin ở đầu bộ đệm tới đối tƣợng nhận. - 136 -
  7. Nhƣ ta thấy trong Chƣong trình 7.5, lớp Queue là lớp dẫn xuất từ Lớp Connector và nó đƣợc sử dụng để kết nối giữa hai đối tƣợng NsObject. Nó khai báo đối tƣợng *pq_ của Lớp PacketQueue (dòng 20) dừng làm bộ đệm gói tin. Kích thƣớc bộ đệm chứa trong biến qlim_ (dòng 16). Các biến blockecL (dòng 17), unblock_on_resume_ (dòng 18) và qh_ (dòng 19) có liên quan tới cơ chế gọi ngƣợc đƣợc trinh bày trong Mục 7.3.3. Có một số hàm quan trọng sau trong Lớp Queue: Hàm enque(p) và deque() (dòng 3-4) thực hiện các công việc tƣơng ứng là đƣa gói tin vào và lấy gói tin ra từ đối tƣợng *pq_ của Lớp PầcketQueue. Các hàm này đều là các hàm ảo nguyên thuỷ và chúng cần đƣợc xây dựng lại trong các Lớp dẫn xuất từ Lớp Queue/Hàm recv(p,h) (dòng 5) thừa kế từ Lớp NsObject là hàm thực hiện việc nhận gói tin. Hàm blocked) (dòng 7) là hàm kiểm tra trạng thái kho á của đối tƣợng Queue. Các hàm resume() (dòng 6), unblock() (dòng 8) và block() (dòng 9) đƣợc sử dụng trong cơ chế gọi ngƣợc sẽ đƣợc đề cập chi tiết trong Mục 7.3.3. Cuối cùng, hàm lỉmito và lengthO thực hiện các công việc tƣơng ứng là lấy giá trị kích cỡ tối đa và kích cỡ hiện tại của bộ đệm.  Lớp PacketQueue Đƣợc khai báo trong Chƣơng trình 7.6, lớp PacketQueue mô hình hoá các hoạt động cấp thấp của bộ đệm bao gồm lƣu trữ, đƣa gói vào hàng đợi và xuất gói ra khỏi hàng đợi. - 137 -
  8. Đối tƣợng PacketQueue là một danh sách liên kết của các con trỏ đối tƣợng Packets. Nó bao gồm các biến và các hàm thành viên sau: 7. Biến head_ (dòng 11): là một con trỏ trỏ vào phần tử đầu danh sách liên kết. 8. Biến tail_ (dòng 12): là một con trỏ trỏ vào phần tử cuối danh sách liên kết 9. Biến len_ (dòng 13); chứa số lƣợng gói tin trong bộ đệm 10.Hàm enque(p) (dòng 5): đƣa gói tin *p vào cuối bộ đệm. 11.Hàm deque() (dòng 6): trả về phần tử con trỏ đầu bộ đệm trong trƣờng hợp bộ đệm không rỗng. Ngƣợc lại nó sẽ trả về giá trị NULL. 12.Hàm remove(p) (dòng 7): tìm kiếm gói tin *p và xoá nó khỏi bộ đệm nếu tìm thấy.  Lớp QueueHandler Lớp QueueHandler là Lớp dẫn xuất từ Lớp Handler (dòng 1 trong Chƣơng trình 7.7). Nó có mối quan hệ chặt chẽ với bộ lập lịch sự kiện. Lớp này định nghĩa hành động mặc định của mình trong hàm handle(e). Các hành động mặc định này sẽ đƣợc thực thi khi sự kiện liên kết với nó đƣợc thực thi. - 138 -
  9. Trong các dòng từ 8 tới 11 của Chƣơng trình 7.7, hành động mặc định của i đối tƣợng QueueHandler là thực hiện lệnh resume của đối tƣợng queue_ (lớp Queue) liên kết với nó. Ta sẽ thảo luận chi tiết về hàm resume trong Mục 7.3.3. Trong phần này ta chỉ tập trung vào nội dung cách tạo ra kết nối giữa các đối tƣợng QueueHandler và đối tƣợng Queue. Để liên kết một đối tƣợng Queue với một đối tƣợng QueueHandler, Lớp Queue khai báo biến thành viên qh_ (dòng 19 trong Chƣong trình 7.5) và Lớp QueueHandler khai báo biến thành viên queue_ (dòng 12 trong Chƣơng trình 7.7). Hai biến này đƣợc khởi tạo khi một đối tƣợng Queue đƣợc tạo ra (dòng 12 trong.Chƣơng trình 7.7). Sau đó, hàm khởi tạo của qh_ thiết lập biến thành viên queue_ để chia sẻ chung địa chỉ của đối tƣợng đầu vào Queue (đối tƣợng queue_(q) trong dòng 3 của Chƣơng trình 7.7). Vỉ vậy kết nối hai chiều giữa đối tƣợng Queue và QueueHandler đã đƣợc tạo ra. Kể từ điểm này, các đối tƣợng Queue và QueueHandler tham chiếu tới nhau bằng các biến qh_ và queue_.  Cơ chế khoá hàng đợi và cơ chế gọi ngƣợc Cơ chế khoá hàng đợi NS2 sử dụng khái niệm ―khoá hàng đợi‖ để chỉ trạng thái hàng đợi đang truyền gói tin. Mặc định, một hàng đợi có thể truyền một gói tin tại một thời điểm. Nó không cho phép (khoá) truyền các gói tin khác cho tới khi hoàn thành việc truyền gói tin hiện tại. Một hàng đƣợc gọi là đang bị khoá (blocked_=l) khi nó đang truyền gói tin và nó có trạng thái mở khoá (blocked_=0) khi nó không truyền gói tin. Hình 7.2. Sơ đồ trạng thái của cơ chế khoá hàng đợi Hình 7.2 cho thấy sơ đồ trạng thái của cơ chế khoá hàng đợi. Khi hàng đợi ở trạng thái ―không khoá‖, nó cho phép truyền gói tin đi bằng cách thực hiệr lệnh ―target_- >recv(p,&qh_)‖. Sau đó nó chuyển sang trạng thái ―khoá‖. ( đây hàng đợi sẽ phải đợi cho đến khi nào việc truyền gói tin ra ngoài hoàj thành. Khi đó hàm resumeO sẽ đƣợc gọi. Sau điểm này, hàng đợi chuyển sanj trạng thái ―không khoá‖ và tiến trình trên lại đƣợc lặp lại. Cơ chế gọi ngƣợc Nhƣ đã đề cập trong Chƣơng 5, một nút trong NS2 truyền các gói tin tc Nút nhận bằng cách thực thi hàm recv(p,h) với *p là gói tin truyền đi và *h là Thẻ quản lý. Cơ chế gọi ngƣợc là tiến trình ở đó đối tƣợng nhận gọi ngƣợc cho đối tƣợng gửi để thực hiện một mục đích nào đó. Trong tiến trình khóa hàng đợi cơ chế gọi ngƣợc đƣợc sử dụng để mở - 139 -
  10. khóa cho một đối tƣợng Queue bằng cách gọi hàm resume) của đối tƣợng Queue ở nút gửi. Bây giờ ta sẽ giải thích chi tiết cơ chế gọi ngƣợc để mở khóa hàng đợi qua ị một ví dụ trong Hình 7.3 Hình 7.3. Sơ đồ của cơ chế gọi ngƣợc dành cho tiến trình mở khóa hàng đợi Trong hình vẽ trên ta giả sử rằng các đối tƣợng sau đã đƣợc kết nối theo thứ tự sau: Đối tƣợng NsObject gửi, đối tƣợng Queue, đối tƣợng LinkDelay và I Đối tƣợng NsObject nhận. Ta cũng nhắc lại rằng, một đối tƣợng NsObject gửi ! gói tin *p bằng cách gọi hàm recv(p,h) của đối tƣợng nhận gói tin, trong đó *h I là Thẻ quản lý. Trong hầu hết mọi trƣờng hợp, Thẻ quản lý đầu vào *I1 đƣợc ; truyền cùng với gói tin *p nhƣ là đối số đầu vào của hàm recv(p,h). Tuy nhiên I cơ chế này lại có sự khác biệt đối với đối tƣợng Queue. Xét hàm recv(p,h) của Lớp Queue trong Chƣơng trình 7.8. Khi đối tƣợng I Queue nhận đƣợc gói tin *p, thay vì việc truyền ngay lập tức gói tin này tới đối I tƣợng nhận của nó, đối tƣợng Queue thực hiện việc đƣa gói tin vào bộ đệm I (dòng 3). Nhắc lại rằng, một đối tƣợng Queue chỉ cho phép truyền một gói tin chỉ khi nó không ở trạng thái khóa (dòng 4). Trong trƣờng hợp này, dòng 5 sẽ lấy về gói tin từ đầu bộ đệm. Nếu gói tin này hợp lệ (dòng 6), dòng 7 sẽ thiết lập trạng thái của đối tƣợng Queue là ―khóa‖ và dòng 8 sẽ chuyển tiếp gói tin này ; tới đối tƣợng nhận kế tiếp của đối tƣợng Queue (chứa trong biến target_). Đối tƣợng Queue truyền con trỏ QueueHandler qh_ của nó (thay vì con trỏ Thẻ quản lý đi tới nó) tới đối tƣợng nhận kế tiếp. Con trỏ QueueHandler này đóng vai trò nhƣ một điểm tham chiếu cho cơ chế gọi ngƣợc mở khóa hàng đợi. - 140 -
  11. Từ Hình 7.3 ta thấy, đối tƣợng nhận kế tiếp của đối tƣợng Queue là đối tƣợng LỉnkDelay. Khi nhận đƣợc một gói tin, đối tƣợng LinkDelay sẽ lập lịch hai sự kiện: sự kiện gói tin rời đi và sự kiện gói tin đi đến (dòng 10 và 8 trong Chƣơng trình 7.4). Sự kiện gói tin đi đến đƣợc liên kết với đối tƣợng nhận kế tiếp (đối tƣợng *target_). Tại thời điểm thực thi, hàm handle(p) của đối tƣợng nhận kế tiếp sẽ gọi hàm recv(p) để nhận gói tin *p (xem Chƣơng trình 4.2). Hàm recv(p) của Lớp LinkDelay cũng đƣợc lập lịch cho sự kiện gói tin rời đi. Vì con trỏ Handler đầu vào là một con trỏ QueueHandler, sự kiện gói tin rời đi đƣợc liên kết với đối tƣợng qh_ kiểu QueueHandler. Tại thời điểm thực thi, bộ lập lịch gọi hàm handle(p) của đối tƣợng QueueHandler qh_. Trong Chƣơng trình 7.7, hàm này sau đó sẽ gọi đến hàm resume() để mở khóa cho đối tƣợng Queue liên kết với nó. Nhƣ vậy có thể thấy đối tƣợng LinkDelay lập lịch cho một sự kiện mà sự kiện này sẽ gọi ngƣợc cho đối tƣợng Queue đã gọi nó để mở khóa hàng đợi. Chƣơng trình 7.9 là mã nguồn của hàm resume(). Đầu tiên hàm này lấy gói tin ở đầu bộ đệm (dòng 3). Nếu bộ đệm không rỗng (dòng 4) thì dòng 5 sẽ gửi gói tin tới đối tƣợng nhận kế tiếp của hàng đợi mà không cần quan tâm tới trạng thái của hàng đợi là khóa hay mở. Trong trƣờng hợp này, biến blocked_ vẫn không có sự thay đổi. Nếu đối - 141 -
  12. tƣợng Queue đang ở trạng thái ―khóa‖, nó sẽ vẫn ở trạng thái khóa sau khi truyền gói tin. Điều này là phù hợp với sơ đồ trạng thái trong Hình 7.2. Nếu hàng đợi rỗi (bộ đệm rỗng), biến blocked. sẽ đƣợc ' thiết lập giá trị bằng 0 nếu cờ unblock_on_resume_ có giá trị bằng 0 và biến blocked_ sẽ đƣợc thiết lập giá trị bằng 1 trong trƣờng hợp cờ , unblock_on_resume_ có giá tri bằng 1.  Lớp DropTail Lớp DropTail là một Lớp con của Lớp Queue. Nó đƣợc liên kết với Lớp Queue/DropTail của OTcl với mã nguồn đƣợc đƣa ra trong Chƣơng trình 7.10. Hàm khởi tạo của Lớp DropTaỉl tạo một con trỏ q_ (dòng 13) trỏ tới một đối tƣợng PacketQueue và thiết lập biến pq_thừa kế từ Lớp Queue bằng giá trị biến q_ (dòng 5). Trong quá trình thực hiện các hàm, Lớp DropTail tham chiếu tới bộ đệm của nó bằng biến con trỏ q_ thay cho biến con trỏ pq_ của Lớp cha. Nó cũng cho phép việc hủy gói tin tại đầu bộ đệm nếu cờ drop_front_ (dòng 14) đƣợc thiết lập giá trị bằng 1. Lớp DropTail không xây dựng lại hàm recv(p,h) từ lớp cha. Do đó, nó nhận gói tin qua hàm tecvíp.h) của Lớp Queue. Trong Chƣơng trình 7.11, hàm enque(p) đầu tiên sẽ kiểm tra gói tin đến có ; làm tràn bộ đệm hay không (dòng 3). Nếu có, hoặc là nó sẽ hủy gỏi tin đang I đứng đầu hàng đợi (dòng 5-7) hoặc là nó sẽ hủy gói tin ở cuối hàng đợi (dòng ! 9). ở đây, hàm drop(p) (dòng 7 và 9) là hàm thành viên của Lớp Connector ; (xem Chƣơng trình 5.4). Nếu bộ đệm còn đủ chỗ, dòng 10 sẽ đƣa gói tin (p) vào I cuối bộ đệm (q_). - 142 -
  13. 7.4. Một ví dụ mạng Two-Node Ta đã giới thiệu về hai thành phần cơ bản của NS2 là nút và kênh truyền. Trên cơ sở của hai thành phần này, bây giờ ta sẽ tạo một mạng gồm hai nút với kênh truyền một chiều và cơ chế chuyển gói tin trong mạng nhƣ Hình 7.4 Hình 7.4. Một mạng hai nút với kênh truyền một chiều và các hàm của lớp Simulator  Khỏi tạo mạng Mạng trong Hình 7.4 bao gồm một nút bắt đầu (n1), một nút kết thúc (n2) một kênh SimpleLink kết nối giữa nl và n2, một tác tử nguồn lớp giao vận(udp) và một tác tử nhận lớp giao vận(null). Mạng này đƣợc tạo ra bởi đoạn mã Tcl sau: Ở đây, lệnh $ns node tạo ra một đối tƣợng Node. Cơ chế bên trong của tiến trình khởi tạo đối tƣợng này đã đƣợc trình bày trong Mục 6.6. Lệnh $ns simplex-link $nl $n2 DropTail tạo một đối tƣợng SimpleLink kết nối một chiều giữa nút nl và nút n2. Băng thông và độ trễ của kênh tƣơng ứng sẽ là bps và giây. Bộ đệm của kênh kiểu DropTail. Nhƣ đã trinh bày trong Mục 6.6.3, lệnh $ns attach-agent $nl $udp thiết lập đích của tác tử udp là đỉểm truy cập của nút n1. Lệnh $n2 attach-agent $n2 $null cài đặt tác tử null vào bộ phân kênh của nút n2.  Cơ chế luồng gói tin - 143 -
  14. Các bƣớc để vận chuyển gói tin ―*p‖ từ tác tử udp tới tác tử null bao gồm: - Tác tử udp gửi gói tin *p tới điểm truy cập của nút nl - Gói tin *p đƣợc gửi tới bộ phân loại đứng đầu classifỉer_ (là đối tƣợng của Lớp DestHastClassifier) của nút nl - Đối tƣợng classifỉer_ lớp DestHashClassỉfier kiểm tra header của gói tin *p. Trong trƣờng hợp này, đích của gói tin là nút n2. Do đó, bộ phân loại này sẽ chuyển tiếp gói tin tới đối tƣợng SimpleLink đứng đầu chuỗi liên kết. - Đối tƣợng SimpleLink chuyển tiếp gói tin tới đối tƣợng Queue - Đối tƣợng Queue đƣa gói tin vào hàng đợi. Nếu hàng đợi ở trạng thái không khóa, nó sẽ chuyển tiếp gói tin đầu hàng đợi tới đối tƣợng LinkDelay kêt nối với nó và thiết lập trạng thái của hàng đợi là trạng thái khóa. - Khi nhận đƣợc gói tin, đối tƣợng LinkDelay lập lịch hai sự kiện - Sự kiện gói tin rời đi chỉ ra rằng việc truyền gói tin đã hoàn thành. Sự kiện này sẽ mở khóa cho hàng đợi Queue liên kết với đối tƣợng LỉnkDelay. - Sự kiện gói tin đi đến chỉ ra rằng gói tin đi đến đối tƣợng TTLChecker kết nối với đối tƣợng LinkDelay - Đối tƣợng TTLChecker nhận gói tin và giảm giá trị của trƣờng TTL I Trong phần header của gói tin. Sau khi giảm giá trị trƣờng TTL, nếu trƣờng I này có giá trị bằng không thì gói tin sẽ bị đối tƣợng này hủy bỏ. Ngƣợc lại, đối tƣợng này chuyển tiếp gói tin tới điểm truy cập của nút n2. Nút n2 chuyển tiếp gói tin tới bộ phân loại đứng đầu classỉfỉer_. Vì ; nút n2 chính là đích của gói tin nên gói tin sẽ đƣợc chuyển tiếp tới bộ phân kênh dmux_i Bộ phân kênh dmux_ chuyển tiếp gói tin tới tác tử null đƣợc cài đặt trong nó. - 144 -
  15. CHƢƠNG 8. PACKETS, PACKETS HEADERS, VÀ HEADERS FORMAT Mục tiêu Một gói tin thông thƣờng bao gồm hai phần là phần header và phần dữ liệu. Header của gói tin lƣu trữ các thông tin thuộc tính của gói cần thiết cho quá trình truyền gói qua mạng trong khi phần dữ liệu lƣu trữ dữ liệu của ngƣời dùng cần truyền qua mạng. Tuy nhiên trong NS2, mô hình gói tin có những sự khác biệt nhất định so với thực tế. Trong hầu hết mọi trƣờng hợp, NS2 trích thông tin từ phần dữ liệu và lƣu thông tin này vào phần header. Ý tƣởng này làm giảm bớt sự cần thiết phải xử lý thông tin trong phần dữ liệu trong thời gian chạy. Ví dụ, thay vì việc phải đếm số lƣợng bit trong gói tin, NS2 lƣu giá trị kích cỡ gói tin trong biến hdr_cmn::size_ (xem Mục 8.3.5) và truy cập vào biến này tại thời gian chạy. Nội dung của chƣơng này tập trung vào vấn đề mô hình hóa gói tin trong NS2. Mục 8.1 đƣa ra một cách nhìn tổng quan về mô hình hóa gói tin trong NS2. Mục 8.2 thảo luận về tiến trình cấp phát và thu hồi bộ nhớ dành cho gói tin. Mục 8.3 và 8.4 đƣa ra nội dung chi tiết về tổ chức phần header và phần dữ liệu của gói tin. Các hƣớng dẫn về cách tùy biến các gói tin đƣợc đƣa ra trong Mục 8.5 8.1. Tổng quan về nguyên tắc tạo gói tin  Kiến trúc gói tin Kiến trúc của một mô hình gói tin trong NS2 đƣợc biểu diễn bởi Hình 8.1. Trong hình vẽ này ta thấy một mô hình gói tin bao gồm bốn thành phần chính: gói tin thực, lớp Packet, header theo giao thức và bộ quản lý header. Ý nghĩa của các thành phần này nhƣ sau: Gói tin thực: Một gói tin thực đƣợc xem nhƣ là một phần của bộ nhớ lƣu trữ phần header và phần dữ liệu của gói tin. NS2 không truy cập trực tiếp tới phần header hoặc phần dữ liệu mà nó sử dụng con trỏ bỉts_ và đata_ để truy cập tƣơng ứng vào phần header và phần dữ liệu của gói tin. Chi tiết về phần header và phần dữ liệu có trong Mục 8.3 và 8.4 của chƣơng này. Lớp Packet: Đƣợc khai báo trong Chƣơng trình 8.1, Lớp Packet là một lớp C++ chính đƣợc dùng để biểu diễn các gói tin. Nó chứa các biến và các hàm thành viên sau: - 145 -
  16. Hình 8.1. Mô hình gói tin trong NS2  Các biến thành viên của lớp Packet bits_: Chuỗi chứa phần header của gói tin data_: Con trỏ trỏ tới một đối tƣợng AppData chứa phần dữ liệu của gói tin fflag_: Đƣợc thiết lập là true nếu gói tin hiện tại đang đƣợc các đối tƣợng khác tham chiếu tới và là false trong trƣờng hợp ngƣợc lại tree_: Con trỏ trỏ tới phần tử đầu danh sách gói tin tự do ref_count_: số lƣợng đối tƣợng đang tham chiếu tới gói tin next_: Con trỏ trỏ tới gói tin tiếp theo trong danh sách liên kết các gói tin. Mr_len_: Kích thƣớc phần header của gói tin.  Các hàm thành viên của lớp Packet - refcopy(): Tăng số lƣợng đối tƣợng tham chiếu vào gói tin lên một đơn vị - alloc(): Tạo một gói tin mới và trạ về một con trỏ trỏ tới gói tin đã đƣợc tạo - alloc(n); Tạo một gói tin mới có ―n‖ byte phần dữ liệu và trả về một con trỏ trỏ tới gói tin đã đƣợc tạo. - 146 -
  17. - allocdata(n): cấp phát ―n‖ byte cho .phần dữ liệu của biến data_ f ree(p): Giải phóng bộ nhớ dành cho gói tin p - access(off): Lấy tham chiếu tới một điểm nào đó (đƣợc xác định bởi khoảng dịch ―off‖) của biến bits_  Header theo giao thức (Protocol Specifỉc Header) Từ Hình 8.1, ta thấy phần header của gói tin chứa một số header theo giao thức. Mỗi header theo giao thức sử dụng một vùng liên tục trong header của gói tin để lƣu các thuộc tính của gói tin. Thông thƣờng với hầu hết các đối tƣợng TclObject, có ba lớp liên quan với mỗi header theo giao thức đó là một lớp C++, một lớp OTcl và một lớp ánh xạ. -Lớp C++ (ví dụ nhƣ hdr_cmn hoặc hdr_ip): cung cấp một cấu trúc để lƣu trữ các thuộc tính của gói tin -Lớp OTcl (ví dụ nhƣ PacketHeader/Common hoặc PacketHeader/IP); đóng vai trò nhƣ một giao tiếp tới miền OTcl. NS2 sử dụng lớp này để cấu hình header của gói tin từ miền OTcl. -Lớp ánh xạ (ví dụ nhƣ CommonHeaderClass hoặc IPHeaderClass); liên kết lớp C++ với lớp OTcl.  Bộ quản lý header (Packet Header Manager) Duy tri một danh sách các giao thức đang hoạt động và cấu hình mọi header theo giao thức đang hoạt động đề thiết lập header của gói tin. Nó có một biến hdrlen_ dùng để - 147 -
  18. lƣu kích thƣớc của phần header của gói tin chứa các header theo giao thức. Biến hdrlen_ đƣợc liên kết với biến hdrlen_ của Lớp Packet. Mọi sự thay đổi của một biến sẽ đƣợc tự động cập nhật sang biến liên kết.  Sự kiện nhận gói tin Đƣợc dẫn xuất từ Lớp Event (dòng 1 trong Chƣơng trình 8.1), Lớp Packet có thể đƣợc đƣa vào dòng thời gian mô phỏng (xem chi tiết trong Chƣơng 4). Trong Mục 4.2, ta đã biết rằng một đối tƣợng Event là một đối tƣợng đƣợc tạo ra bởi ngƣời dùng từ mã Tcl. Chƣơng này sẽ thảo luận chi tiết về một Lớp khác dẫn xuất từ Lớp Event. Đó là Lớp Packet. Nhƣ đã nói đến trong Mục 5.2.2, NS2 mô hình hóa sự kiện làm trễ quá trình truyền gói tin bằng cách đƣa một sự kiện tƣơng ứng vào dòng thời gian mô phỏng với một khoảng thời gian trễ xác định trƣớc. Đƣợc dẫn xuất từ Lớp Event, lớp Packet có thể đƣợc đƣa vào dòng thời gian mô phỏng để biểu diễn việc nhận một gói tin bị trễ. Ví dụ, câu lệnh sau (xem dòng 8 trong Chƣơng trinh 7.4) lập lịch một sự kiện nhận gói tin để đối tƣợng *target_ kiểu NsObject nhận gói tin *p tại thời điểm txt+delay_ giây trong tƣơng lai: s.schedule(target_, p, txt + delay_) Hàm schedule(-) của lớp Scheduler đƣợc định nghĩa trong Chƣơng trinh 4.7 có đối số đầu vào thứ hai là một con trỏ Event. Con trỏ Packet có thể đƣợc ép kiểu thành con trỏ Event trƣớc khi đƣa vào làm tham số thứ hai của hàm trên. Tại thời điểm thực thi sự kiện, bộ lập lịch sẽ thực thi sự kiện đƣợc lập lịch (*p) và gọi hàm target―>handle(p) đề thực thi hàm ―target->recv(p)‖ để chuyển tiếp gói tin *p tới con trỏ đối tƣợng *target_ lớp NsObject. - Danh sách lỉên kết gói tin Là một trong bốn thành phần chính của gói tin trong NS2, một đối tƣợng Packet chứa một con trỏ next_ (dòng 11 trong Chƣong trinh 8.1) để trợ giúp cho việc hình thành một danh sách các đối tƣợng Packet (ví dụ nhƣ Packet List trong Hình 8.2). Hình 8.2. Danh sách liên kết các gói tin và danh sách gói tin tự do - 148 -
  19. Chƣơng trình 8.2 đƣa ra mã thực hiện của các hàm enque(p) và deque(p) cửa lớp PacketQueue. Hàm enque(p) (dòng 3-13) thêm một đối tƣợng *p kiểu Packet vào cuối hàng đợi. Nếu hàng đợi PacketQueue rỗng, NS2 sẽ thiết lập các con trỏ head_, tail_ và p trỏ tới cùng một điểm (dòng 5). Ngƣợc lại, dòng 7-8 thiết lập con trỏ p trỏ vào gói tin ở cuối hàng đợi PacketQueue và dịch chuyển con trỏ tail_ trỏ vào cùng vị trí với con trỏ p. Vì con trỏ tail_ là con trỏ cuối cùng của hàng đợi PacketQueue nên dòng 10 thiết lập con trỏ tail_- >next_ bằng 0 (trỏ đến NULL). Hàm deque (dòng 14-21) lấy về một con trỏ trỏ tới gói tin đầu bộ đệm. Nếu không có gói tin nào trong bộ đệm, hàm deque() sẽ trả lại con trỏ NULL (dòng 15). Nếu bộ đệm không rỗng, dòng 17 sẽ dịch chuyển con trỏ head_ tới gói tin tiếp theo, dòng 19 sẽ trả về con trỏ gói tin p đã đƣợc thiết lập là con trỏ head_ trong dòng 16. Danh sách gói tin tự do Không nhƣ hầu hết các đối tƣợng NS2 khác, đối tƣợng Packet mỗi khi đƣợc tạo ra sẽ không bị hủy cho đến khi kết thúc mô phỏng. NS2 sẽ lƣu giữ các đối tƣợng Packet không còn sử dụng trong một danh sách gói tin tự do (xem Hình 8.2). Khi NS2 cần một gói tin mới, đầu tiên nó sẽ kiểm tra xem danh sách gói tin tự do có rỗng hay không. Nếu không rỗng, nó sẽ lấy một đối tƣợng Packet từ danh sách này. Nếu danh sách này rỗng, nó sẽ tạo một đối tƣợng Packet mới. Ta sẽ thảo luận chi tiết về quá trình cấp phát và thu hồi bộ nhớ cho đối tƣợng Packet trong Mục 8.2. Có hai biến có mối quan hệ rất chặt chẽ với tiến trinh cấp phát và thu hồi bộ nhớ là biến fflag_ và free_. Ngƣởi ta sử dụng biến fflag_ (dòng 6 trong Chƣơng trinh 8.1) của một đối tƣợng Packet để xác định xem đối tƣợng này có đang đƣợc sử dụng hay không. Nếu biến fflag_ có giá tộ true thì hiện tại nó đang đƣợc sử dụng và ngƣợc lại biến này sẽ có giá trị false. Con trỏ tĩnh free_ (dòng 8 trong Chƣơng trình 8.1) đƣợc mọi đối tƣợng - 149 -
  20. Packet sử dụng chung là một con trỏ trỏ vào gói tin đầu tiên của danh sách gói tin tự do. Mỗi một gói tin trong danh sách gói tin tự do sử dụng biến next_ của mình để trợ giúp cho quá trình thiết lập danh sách liên kết các đối tƣợng gói tin tự do. Mặc dù NS2 không trả về bộ nhớ đƣợc cấp phát cho một đối tƣợng Packet cho hệ thống, nó vẫn thực hiện việc trả về bộ nhớ đƣợc phần header và phần dữ liệu của gói tin sử dụng (biến bits_ và data_) cho hệ thống (xem Mục 8.2.2). Vì yêu cầu lƣu trữ một đối tƣợng gói tin trong bộ nhớ là tổng họp của phần header và phần dữ liệu cho nên việc duy trì danh sách gói tin tự do sẽ tiết kiệm đƣợc nhiều không gian bộ nhớ. 8.2. Sắp xếp và phân bổ gói tin Không giống nhƣ hầu hết các đối tƣợng NS2 khác, một đối tƣợng Packet đƣợc NS2 cấp phát và thu hồi bộ nhớ bằng cách sử dụng các hàm tĩnh tƣơng ứng là alloc() và free(). Nếu có thể, hàm alloc() sẽ lấy một đối tƣợng Packet từ danh sách các gói tin tự do. Chỉ khi nào danh sách này rỗng, nó mới tạo ra một đối tƣợng Packet mới bằng cách sử dụng hàm new. Hàm free(p) thu hồi bộ nhớ đã cấp phát cho một đối tƣợng Packet bằng cách trả về vị trí bộ nhớ đã đƣợc cấp phát cho phần header và phần dữ liệu của đối tƣợng này cho hệ thống và lƣu trữ con trỏ p trỏ tới gói tin không đƣợc sử dụng vào danh sách gói tin tự do để có thể sử dụng lại sau đó. Chi tiết của tiến trình cấp phát và thu hồi bộ nhở cho đối tƣợng Packet đƣợc trình bày ở hai mục tiếp theo là 8.2.1 và 8.2.2. 8.1.1. Cấp phát gói tin Chƣơng trình 8.3 đƣa ra chi tiết của hàm alloc() thuộc lớp Packet. Hàm alloc() trả về một con trỏ trỏ tới một đối tƣợng Packet đƣợc cấp phát cho đối tƣợng gọi hàm. Nó bao gồm hai phần: cấp phát gói tin trong các dòng 3-15 và khởi tạo gói tin trong các dòng 16-24. Xét tiến trình cấp phát gói tin trong các dòng 3-15. Dòng 3 khai báo p là con trỏ trỏ tới đối tƣợng Packet và thiết lập con trỏ p trỏ tới gói tin đầu tiên trong danh sách gói tin tự do. Nếu danh sách này rỗng (p=0), NS2 sẽ tạo một đối tƣợng Packet mới (dòng 11), và cấp phát không gian nhớ có kích thƣớc ―ỉiđrlen^‘ byte cho phần header của gói tin trong dòng 12. Biến hdrlen_ không đƣợc cấu hình trong quá trình khởi tạo đối tƣợng Packet. Thay vào đó, nó đƣợc thiết lập trong Pha cấu hình mạng (xem Mục 8.3.8) và đƣợc hàm alloc() sử dụng để tạo header của gói tin. Hàm alloc() không cấp phát bộ nhớ cho phần dữ liệu của gói tin. Nếu cần thì NS2 sẽ tạo phần này bằng hàm allocdata(n) (dòng 8-14 trong Chƣơng trình 8.4). - 150 -
nguon tai.lieu . vn