Xem mẫu
- 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 -
- đƣợ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 -
- 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 -
- đƣợ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 -
- 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 -
- 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 -
- 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 -
- Đố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 -
- 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 -
- 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 -
- 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 -
- 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 -
- 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 -
- 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 -
- 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 -
- 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 -
- - 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 -
- 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 -
- 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 -
- 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