第一篇:ucore實驗3實驗報告
LAB3實驗報告
實驗目的:
? 了解虛擬內存的Page Fault異常處理實現 ? 了解頁替換算法在操作系統中的實現 實驗內容:
本次實驗是在實驗二的基礎上,借助于頁表機制和實驗一中涉及的中斷異常處理機制,完成Page Fault異常處理和FIFO頁替換算法的實現,結合磁盤提供的緩存空間,從而能夠支持虛存管理,提供一個比實際物理內存空間“更大”的虛擬內存空間給系統使用。這個實驗與實際操作系統中的實現比較起來要簡單,不過需要了解實驗一和實驗二的具體實現。實際操作系統系統中的虛擬內存管理設計與實現是相當復雜的,涉及到與進程管理系統、文件系統等的交叉訪問。如果大家有余力,可以嘗試完成擴展練習,實現extended clock頁替換算法。
一.練習
練習0:填寫已有實驗
本實驗依賴實驗1/2。請把你做的實驗1/2的代碼填入本實驗中代碼中有“LAB1”,“LAB2”的注釋相應部分。
練習1:給未被映射的地址映射上物理頁
完成do_pgfault(mm/vmm.c)函數,給未被映射的地址映射上物理頁。設置訪問權限 的時候需要參考頁面所在VMA的權限,同時需要注意映射物理頁時需要操作內存控制 結構所指定的頁表,而不是內核的頁表。注意:在LAB2 EXERCISE 1處填寫代碼。執行
make qemu后,如果通過check_pgfault函數的測試后,會有“check_pgfault()succeeded!”的輸出,表示練習1基本正確。
請在實驗報告中簡要說明你的設計實現過程。請回答如下問題: ? 請描述頁目錄項(Pag Director Entry)和頁表(Page Table Entry)中組成部分對ucore實現頁替換算法的潛在用處。
? 如果ucore的缺頁服務例程在執行過程中訪問內存,出現了頁訪問異常,請問硬件要做哪些事情?
問題分析:當啟動分頁機制以后,如果一條指令或數據的虛擬地址所對應的物理頁不在內存中,或者訪問權限不夠,那么就會產生頁錯誤異常。其具體原因有以下三點: 1.頁表項全為0——虛擬地址與物理地址為建立映射關系或已被撤銷。2.物理頁面不在內存中——需要進行換頁機制。3.訪問權限不夠——應當報錯。
根據以上三點錯誤原因,完成頁錯誤處理函數do——pgfault()。
大體思路:do_pgfault()函數從CR2寄存器中獲取頁錯誤異常的虛擬地址,根據error code來查找這個虛擬地址是否在某一個VMA的地址范圍內,并且具有正確的權限。如果滿足上述兩個要求,則需要為分配一個物理頁。程序代碼:
Kern/mm/vmm.c中do_pgfault()函數的EXERCISE 1修改如下: //嘗試找到pte, 如果對應的頁表項PT不存在則創建一個
//這里調用函數get_pte(pde_t *pgdir, uintptr_t la, bool create), 其中create=1表示若PT不存在則允許創建
if((ptep = get_pte(mm->pgdir, addr, 1))== NULL){//嘗試查找頁表入口
cprintf(“get_pte in do_pgfault failedn”);//如果找不到入口,是非法訪問,退出
goto failed;
}
//如果物理地址不存在,則建立一個邏輯地址和物理地址的映射 //perm為VMA的權限
if(*ptep == 0){ //嘗試申請一個頁,如果申請失敗就是內存不足了,退出
if(pgdir_alloc_page(mm->pgdir, addr, perm)== NULL){
cprintf(“pgdir_alloc_page in do_pgfault failedn”);
goto failed;
} }
思考題:
1.請描述頁目錄項(Page Director Entry)和頁表(Page Table Entry)中組成部分對ucore實現頁替換算法的潛在用處。
Ans.頁目錄項(pgdir)作為一個雙向鏈表存儲了目前所有的頁的物理地址和邏輯地址的對應,即在實內存中的所有頁,替換算法中被換出的頁從pgdir中選出。頁表(pte)則存儲了替換算法中被換入的頁的信息,替換后會將其映射到一物理地址。
2.如果ucore的缺頁服務例程在執行過程中訪問內存,出現了頁訪問異常,請問硬件要做哪些事情?
Ans.產生頁訪問異常后,CPU把引起頁訪問異常的線性地址裝到寄存器CR2中,并給出了出錯碼errorCode,說明了頁訪問異常的類型。ucore OS會把這個值保存在struct trapframe 中tf_err成員變量中。而中斷服務例程會調用頁訪問異常處理函數do_pgfault進行具體處理。
練習2:補充完成基于FIFO的頁面替換算法(需要編程)完成vmm.c中的do_pgfault函數,并且在實現FIFO算法的swap_fifo.c中完成map_swappable和swap_out_vistim函數。通過對swap的測試。注意:在LAB2 EXERCISE 2處填寫代碼。執行make qemu后,如果通過check_swap函數的測試后,會有“check_swap()succeeded!”的輸出,表示練習2基本正確。
請在實驗報告中簡要說明你的設計實現過程。請在實驗報告中回答如下問題: ? 如果要在ucore上實現“extended clock頁替換算法”請給你的設計方案,現有的swap_manager框架是否足以支持在ucore中實現此算法?如果是,請給你的設計方案。如果不是,請給出你的新的擴展和基此擴展的設計方案。并需要回答如下問題 ? 需要被換出的頁的特征是什么?
? 在ucore中如何判斷具有這樣特征的頁? ? 何時進行換入和換出操作?
問題分析:根據練習1,當頁錯誤異常發生時,有可能是因為頁面保存在swap區或者磁盤文件上造成的,練習2需要利用頁面替換算法解決這個問題。大體思路:頁面替換主要分為兩個方面,頁面換出和頁面換入。頁面換入主要在vmm.c中的do_pgfault()函數實現:頁面換出主要在swap_fifo.c中的swap_out_vistim()函數實現。
在換入時,需要先檢查產生訪問異常的地址是否屬于某個vma表示的合法虛擬地址,并且保存在硬盤的swap文件中(對應的PTE的高24位不為0)。如果滿足以上兩點,則執行swap_in()函數換入頁面。
換出則相對簡單,當申請空閑頁面時,alloc_pages()函數不能獲得空閑頁,則需要調用swap_out()函數函數換出不常用的頁面。程序代碼:
Kern/mm/vmm.c中do_pgfault()函數的EXERCISE 2修改如下: else {
//如果pte是需要交換的表項,那么就從硬盤的物理地址將數據讀到頁中
//然后調用page_insert()建立物理地址和邏輯地址映射
if(swap_init_ok){
struct Page *page=NULL;//根據mm結構和addr地址,嘗試將硬盤中的內容換入至page中 //此時的page還沒有加入到隊列中
if((ret = swap_in(mm, addr, &page))!= 0){//ret=0表示swap_in()正常運行結束
cprintf(“swap_in in do_pgfault failedn”);
goto failed;
}
//建立虛擬地址合物理地址之間的對應關系
page_insert(mm->pgdir, page, addr, perm);//將此頁面設置成可交換的
swap_map_swappable(mm, addr, page, 1);
}
else {
cprintf(“no swap_init_ok but ptep is %x, failedn”,*ptep);
goto failed;}
Kern/mm/swap_fifo.c中的EXERCISE 2修改如下:
_fifo_map_swappable(struct mm_struct *mm, uintptr_t addr, struct Page *page, int swap_in){//將最近被用到的頁面添加到算法所維護的次序隊列
//找到pra_list_head隊列
list_entry_t *head=(list_entry_t*)mm->sm_priv;//找到被換入的頁表項
list_entry_t *entry=&(page->pra_page_link);
assert(entry!= NULL && head!= NULL);
/*LAB3 EXERCISE 2: YOUR CODE*/
//將最近分配的頁插入到pra_list_head隊列的尾部.list_add_before(head, entry);
return 0;}
_fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick){//查詢哪個頁面需要被換出
//找到pra_list_head隊列
list_entry_t *head=(list_entry_t*)mm->sm_priv;
assert(head!= NULL);
assert(in_tick==0);
//選擇應該被換出的頁表,即FIFO中最早調入的頁表
list_entry_t *le = head->next;
assert(le!= head);
/*LAB3 EXERCISE 2: YOUR CODE*/
//將換出的頁表從pra_list_head隊列中刪除
struct Page *p = le2page(le, pra_page_link);
list_del(le);
assert(p!= NULL);
//將頁的地址的地址賦值給ptr_page
*ptr_page = p;
return 0;} 思考題:如果要在ucore上實現“extended clock頁替換算法”請給你的設計方案,現有的swap_manager框架是否足以支持在ucore中實現此算法?如果是,請給你的設計方案。如果不是,請給出你的新的擴展和基此擴展的設計方案。
答:目前的swap_manager框架足以支持在ucore中實現extended clock算法。
在kern/mm/mmu.h文件中有如下定義:
#define PTE_A
0x020
// Accesseed 所以(*ptep & PTE_A)即可以表明該頁是否被訪問過,由此實現extended clock。于是對kern/mm/vmm.h做相應的修改:
_fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick){
list_entry_t *head =(list_entry_t*)mm->sm_priv;
assert(head!= NULL);
assert(in_tick == 0);
list_entry_t *le = head->next;
assert(head!= le);
while(le!= head){
struct Page *p = le2page(le, pra_page_link);
pte_t *ptep = get_pte(mm->pgdir, p->pra_vaddr, 0);
if(!(*ptep & PTE_A)){ //未被訪問
list_del(le);
assert(p!= NULL);
*ptr_page = p;
return 0;
}
}
*ptep ^= PTE_A;
le = le->next;} le = le->next;while(le!= head){
struct Page *p = le2page(le, pra_page_link);
pte_t *ptep = get_pte(mm->pgdir, p->pra_vaddr, 0);
list_del(le);
assert(p!= NULL);
*ptr_page = p;
return 0;} ① 需要被換出的頁的特征是什么?
答:在FIFO中,需要被換出的頁是目前所有頁中最早被調入的那一頁。
② 在ucore中如何判斷具有這樣特征的頁?
答:需要被換出的頁位于pra_list_head隊列的前端,即mm->sm_priv->next指示的那一頁。
③ 何時進行換入和換出操作?
答:當需要調用的頁不在頁表中時,并且在頁表已滿的情況下,需要進行換入和換出操作。
擴展練習Challenge:實現識別dirty bit的extended clock頁替換算法(需要編程)問題分析:算法根據頁面近期是否被修改從而決定該頁面是否應當被換出。所以在查詢空閑頁時,需要加上對dirty bit的判斷。
大體思路:當操作系統需要淘汰頁時,對當前指針指向的頁所對應的頁表項進行查詢,如果dirty bit為0,則把此頁換出到硬盤上;如果dirty bit為1,則將dirty bit置為0,繼續訪問下一個頁。程序代碼:
相比較FIFO的操作,dirty bit的替換算法只需要識別出哪些頁被訪問過,以及哪些頁被修改過即可。在kern/mm/mmu.h文件下有如下的定義:
#define PTE_A
0x020
// Accessed #define PTE_D
0x040
// Dirty 其中PTE_A和PTE_D分別是表示訪問和修改的標識位,因此與*ptep求與即可判斷頁是否被訪問或修改過。首先根據基礎的extended clock算法,未被訪問的頁應優先考慮換出;在此基礎上,由于被修改的也需要被寫會硬盤,因此未被修改的頁應該有限換出。因此采用多輪循環。只需要修改kern/mm/vmm.h中的_fifo_swap_out_victim()函數即可實現: _fifo_swap_out_victim(struct mm_struct *mm, struct Page ** ptr_page, int in_tick){
list_entry_t *head =(list_entry_t*)mm->sm_priv;
assert(head!= NULL);
assert(in_tick == 0);//將head指針指向最先進入的頁面
list_entry_t *le = head->next;
assert(head!= le);
//查找最先進入并且未被修改的頁面
while(le!= head){
struct Page *p = le2page(le, pra_page_link);//獲取頁表項
pte_t *ptep = get_pte(mm->pgdir, p->pra_vaddr, 0);
//判斷獲得的頁表項是否正確
if(!(*ptep & PTE_A)&&!(*ptep & PTE_D)){
//如果dirty bit為0,換出
//將頁面從隊列中刪除
list_del(le);
assert(p!= NULL);//將這一頁的地址存儲在prt_page中
*ptr_page = p;
return 0;} le = le->next;
//未被訪問,未被修改
} le = le->next;while(le!= head){
struct Page *p = le2page(le, pra_page_link);
pte_t *ptep = get_pte(mm->pgdir, p->pra_vaddr, 0);
if(!(*ptep & PTE_A)&&(*ptep & PTE_D)){ //未被訪問,已被修改
list_del(le);
assert(p!= NULL);
*ptr_page = p;
return 0;
}
*ptep ^= PTE_A;//頁被訪問過則將PTE_A位置0
le = le->next;
}
le = le->next;
while(le!= head){
struct Page *p = le2page(le, pra_page_link);
pte_t *ptep = get_pte(mm->pgdir, p->pra_vaddr, 0);
if(!(*ptep & PTE_D)){ //未被修改,此時所有頁均被訪問過,即PTE_A位為0
list_del(le);
assert(p!= NULL);
*ptr_page = p;
return 0;
}
le = le->next;
}
//如果這行到這里證明找完一圈,所有頁面都不符合換出條件
//那么強行換出最先進入的頁面
} le = le->next;while(le!= head){
struct Page *p = le2page(le, pra_page_link);
pte_t *ptep = get_pte(mm->pgdir, p->pra_vaddr, 0);
} if(*ptep & PTE_D){ //已被修改
list_del(le);
assert(p!= NULL);//將這一頁的地址存儲在ptr_page中
*ptr_page = p;
return 0;} le = le->next;
運行截圖:
二.實驗分析與總結
本次實驗主要完成ucore內核對虛擬內存的管理工作。其總體設計思路還是比較簡單,即首先完成初始化虛擬內存管理機制,即需要設置好哪些頁需要放在物理內存中,哪些頁不需要放在物理內存中,而是可被換出到硬盤上,并涉及完善建立頁表映射、頁訪問異常處理操作等函數實現。然后就執行一組訪存測試,看看我們建立的頁表項是否能夠正確完成虛實地址映射,是否正確描述了虛擬內存頁在物理內存中還是在硬盤上,是否能夠正確把虛擬內存頁在物理內存和硬盤之間進行傳遞,是否正確實現了頁面替換算法等。
第二篇:交換機實驗 實驗報告
交換機實驗II 實驗目的
1.理解掌握環路對網絡造成的影響,掌握環路的自檢測的配置; 2.理解路由的原理,掌握三層交換設備路由的配置方法 3.掌握DHCP的原理以及其配置方法
實驗步驟
配置交換機的IP地址,及基本的線路連接等; 實驗1:
①.用獨立網線連接同一臺交換機的任意兩個端口時期形成自環
②.對交換機的兩個端口進行配置,開啟所有端口的環路檢測功能、設置檢測周期等屬性 實驗2:
①.按圖1方式對三層交換機的VLAN、端口進行配置
②.在交換機中分別對VLAN的IP地址進行配置
③.啟動三層交換機的IP路由
④.設置PC-A、PC-B的IP地址,分別將它們的網關設置為所屬三層交換機VLAN的IP地址
⑤.通過Ping驗證主機A、B之間的互通狀況 實驗3:
三層交換機作為DHCP服務器,兩臺PC-A和PC-B,分別從交換機上獲取IP地址。PC-C手動配置IP地址。
①.按圖2方式建立主機A、B、C與三層交換機間的連接,配置交換機的IP地址
②.配置三層交換機的DHCP地址池屬性
③.啟動DHCP服務
④.(1)查看主機A、B能否正確的獲取到給定范圍內IP地址,通過Ping查看網關、交換機之間的互通情況;(2)拔掉主機B的網線,將主機C的IP地址設置為主機B所獲取的到的IP地址,然后再插上B機網線,查看其是否能獲取到不同的IP地址;(3)分別重啟主機A、B及交換機,查看A、B獲取到的IP地址是否和前一次相同。
圖1.三層路由連接圖
圖2.DHCP連接圖
實驗結果
實驗1:環路測試
交換機出現環路的自檢測結果:
實驗2:路由配置:
主機A連接交換機端口2,劃分為vlan10,端口IP地址為192.168.1.1。主機IP地址192.168.1.23;
主機B連接交換機端口10,劃分為vlan20,端口IP地址為192.168.2.1。主機IP地址192.168.2.27;
在未設置IP routing之前主機A、B分屬于不同網段,因此它們不能互通,設置后通過路由則可相互聯通:
實驗三:DHCP配置和驗證:
主機A、B、C分別連接到交換機的端口2,端口18和端口10上。其中主機A、B的IP地址自動獲取,主機C的IP地址則手動配置。
主機A通過DHCP獲取的IP地址(192.168.1.211)
主機B通過DHCO獲取到的IP地址(192.168.1.210)
測試主機A與主機C的互通性(可連通)
測試主機B與主機A、C之間的互通性(可連通)
當主機C配置為主機B獲取到的IP地址是會產生IP地址沖突的錯誤提示:
配置的主機C的IP地址與主機B的IP地址相沖突
主機B網線重新連接后獲取到的新的IP地址
交換機重新啟動后A、B主機自動獲取到的IP地址信息:
主機A自動獲取的IP地址
主機B自動獲取的IP地址
DHCP可分配IP地址池內IP數目小于申請的主機數目時實驗驗證情況:(可分配的IP地址為192.168.1.210 — 192.168.1.212),此時連接主機A、B、C、D。
主機D自動獲取IP地址的結果
實驗與結果分析
環路問題:
分為第二層環路和第三層環路,所有環路的形成都是由于目的路徑不明確導致混亂而造成的。例如第二層,一個廣播信息經過兩個交換機的時候會不斷惡性循環的產生廣播造成環路,而第三層環路則是原路由意外不能工作,造成路由通告錯誤,形成一個惡性循環。傳統的二層預防技術主要有STP(Spanning tree)來預防,STP在不斷的修改和更新中,產生了諸如STP/RSTP/MSTP等多個版本,大家可根據各自的組網規劃來選擇應用,但是STP的配置復雜度,以及協議本身的開銷通常都是網絡管理人員比較頭痛的事情。
解決因環路(自環或外環)對網絡造成的影響,能夠提高網絡的自檢錯性、容錯性和健壯性。環路檢測的過稱為:對交換機的每個端口周期性的發送回路檢測(Loopback-detection)數據包;交換機查看端口收到包的CPUMAC字段,如果其中存的是本交換機的MAC,則本交換機的某些端口形成環路,否則將其丟棄,出現環路后,交換機會關閉端口號較大的端口以消除環路。圖1中反映了在交換機開啟所有端口的環路檢測功能后每隔30秒檢測到的信息以及對端口的關閉等操作信息。
三層路由意義和工作過程: 實現不同VLAN間主機的通信,通過配置VLAN能夠有效地控制廣播域的大小。在同一VLAN內的主機間的通信不需要經過交換機的路由處理可直接到達目的主機,當不同VLAN間通訊時,數據包先轉發至路由器,由路由器查詢其路由轉發表選擇正確的端口間數據包轉發到目的VLAN的交換機,再由目的VLAN內交換機將數據包轉發至目的主機。其中扮演主要角色的即為交換機的路由功能,如果沒有設置相關屬性則不同VLAN間不能通訊。
因此在圖3的驗證實驗中,通過路由器的轉發功能實現了分別位于VLAN10和VLAN20中主機A、B之間的通信,在未配置IP Routing之前VLAN10和VLAN20分屬不同網段(A、B也屬于不同網段),因此不能實現通信,配置之后路由器(三層交換設備)可通過內部路由轉發表實現數據的轉發和通信。
DHCP工作過程與實驗分析:
即動態主機配置協議(Dynamic Host Configuration Protocol),是一個局域網的網絡協議,使用UDP協議工作,主要有兩個用途:給內部網絡或網絡服務供應商自動分配IP地址,是使內部網絡管理員能夠集中管理(從中心結點監控)和自動分配IP 網絡地址的通信協議。當某臺計算機移到網絡中的其它位置時,能自動收到新的IP 地址。DHCP 服務器從地址池中為客戶端選擇并分配IP 地址及其他相關參數當作為DHCP服務器的設備收到客戶端發來的DHCP 請求時,將從地址池中挑選一個空閑的IP 地址。
DHCP工作過程:
當 DHCP客戶端第一次登錄網絡的時候,也就是客戶發現本機上沒有任何 IP 數據設定,它會向網絡發出一個 DHCP DISCOVER封包(廣播包)。因為客戶端還不知道自己屬于哪一個網絡,所以封包的來源地址會為 0.0.0.0,而目的地址則為 255.255.255.255,然后再附上 DHCP discover 的信息,向網絡進行廣播。如果都沒有得到DHCP服務器的響應,客戶端則會顯示錯誤信息,宣告 DHCP discover 的失敗。之后,基于使用者的選擇,系統會繼續在 5 分鐘之后再重復一次 DHCP discover 的過程。
當 DHCP服務器監聽到客戶端發出的 DHCP discover 廣播后,它會從那些還沒有租出的地址范圍內,選擇最前面的空置 IP,連同其它 TCP/IP 設定,響應給客戶端一個 DHCP OFFER封包。由于客戶端在開始的時候還沒有 IP 地址,所以在其 DHCP discover封包內會帶有其 MAC 地址信息,并且有一個 XID 編號來辨別該封包,DHCP服務器響應的 DHCP offer 封包則會根據這些資料傳遞給要求租約的客戶。根據服務器端的設定,DHCP offer封包會包含一個租約期限的信息。
如果客戶端收到網絡上多臺 DHCP 服務器的響應,只會挑選其中一個 DHCP offer 而已(通常是最先抵達的那個),并且會向網絡發送一個DHCP request廣播封包,告訴所有 DHCP 服務器它將指定接受哪一臺服務器提供的 IP 地址。同時,客戶端還會向網絡發送一個 ARP封包,查詢網絡上面有沒有其它機器使用該 IP 地址;如果發現該 IP 已經被占用,客戶端則會送出一個 DHCPDECLINE 封包給 DHCP服務器,拒絕接受其 DHCP offer,并重新發送 DHCP discover 信息。事實上,并不是所有 DHCP客戶端都會無條件接受 DHCP服務器的 offer,尤其這些主機安裝有其它 TCP/IP 相關的客戶軟件。客戶端也可以用 DHCP request 向服務器提出 DHCP 選擇,而這些選擇會以不同的號碼填寫在 DHCP Option Field 里面。
當 DHCP服務器接收到客戶端的 DHCP request 之后,會向客戶端發出一個DHCPACK 響應,以確認 IP 租約的正式生效,標志著一次DHCP的工作過程完成。
圖4—6反映了主機A、B通過自動獲取IP地址方式由三層交換機動態分配IP后,各自得到的IP地址,由于A、B、C連接與同一臺交換設備上,由沒有VLAN劃分等因素,所以它們之間不論是自動獲取IP地址還是手動配置IP地址(不沖突的前提下)都能相互連通。當為主機C配置成已得到自動分配IP地址的主機B的IP地址時,自然會出現IP地址沖突的出錯信息提示。當B網線重新鏈接時,相當于重新加入的客戶端,交換機會從地址池中順序選擇下一個未分配的IP地址給新的請求用戶。因此主機B會獲得新新的IP地址,并且其值是主機C的IP地址的下一個鄰接IP地址(在未超出可分配的IP地址范圍條件下)。圖7 —10中反映了上述描述的結果。
圖11中顯示了一種造成IP地址動態分配失敗的情形:可分配的IP地址數僅有3個,而由4臺主機請求分配IP地址,當可分配地址全部分配給主機A、B、C后,主機D的請求不能得到滿足,因此未得到給定范圍內的合理IP地址。
第三篇:實驗一 實驗報告
網 絡 程 序 設 實驗報告
實驗名稱:Winsock編程接口實驗 實驗類型: 驗 證 型
計
一、實驗目的
? 掌握Winsock的啟動和初始化;
? 掌握gethostname(),gethostbyname(),GetAdaptersInfo()等信息查詢函數的使用。
二、實驗設計
實驗內容:
1、編寫程序能同時實現對多個域名的解析。比如在控制臺輸入:getip www.tmdps.cn對應的IP地址列表。
2、編寫程序獲取并輸出本地主機的所有適配器的IP地址,子網掩碼,默認網關,MAC地址。
根據實驗內容編寫程序:
1、對相關域名進行解析,利用gethostbyname()完成解析,用到的結構體為:
struct hostent{ char FAR*
h_name;char FAR* FAR* h_aliases;short
h_addrtype;short
h_length;char FAR* FAR* h_addr_list;}
得到的IP地址列表由h_addr_list存儲;
2、利用GetAdaptersInfo()函數獲得本地主機的相關信息,通過IP_ADAPTER_INFO結構體返回所需信息。
IP_ADAPTER_INFO的定義如下: typedef struct _IP_ADAPTER_INFO {
struct _IP_ADAPTER_INFO* Next;
DWORD ComboIndex;
char AdapterName[MAX_ADAPTER_NAME_LENGTH + 4];
char Description[MAX_ADAPTER_DESCRIPTION_LENGTH + 4];
UINT AddressLength;
BYTE Address[MAX_ADAPTER_ADDRESS_LENGTH];
DWORD Index;
UINT Type;
UINT DhcpEnabled;
PIP_ADDR_STRING CurrentIpAddress;
IP_ADDR_STRING IpAddressList;
IP_ADDR_STRING GatewayList;
IP_ADDR_STRING DhcpServer;
BOOL HaveWins;
IP_ADDR_STRING PrimaryWinsServer;
IP_ADDR_STRING SecondaryWinsServer;
time_t LeaseObtained;
time_t LeaseExpires;
} IP_ADAPTER_INFO, *PIP_ADAPTER_INFO;
三、實驗過程(包含實驗結果)
1、分析題目,編寫程序;
2、將編寫的程序進行編譯、運行,輸入題目給定的內容,完成題目要求; 結果如下:
第1題:
第2題:
四、討論與分析
思考題:
1、Winsock初始化的作用:只有調用了WSAStartup()進行初始化之后,應用程 序才能調用其他Windows Sockets API函數,實現網絡通信;
2、函數原型為:
DWORD GetAdaptersInfo(PIP_ADAPTER_INFO pAdapterInfo,//接受數據的緩沖區
PULONG pOutBufLen
// 數據的長度大小);
3、域名解析時出現域名對應多個IP,原因:該域名存在于多個服務器。
五、實驗者自評
通過本次實驗,我掌握了Winsock的啟動和初始化以及gethostname(),gethostbyname(),GetAdaptersInfo()等函數查詢的使用,加深了以前對課本知識的認識程度。
六、附錄:關鍵代碼(給出適當注釋,可讀性高)
第1題代碼:
////////////////////////////////////////////////// // GetAllIps.cpp文件
//#include “../common/InitSock.h” #include
using namespace std;
#pragma comment(lib, “WS2_32”)// 鏈接到WS2_32.lib //CInitSock initSock;// 初始化Winsock庫
void main(){
char szMessage[256];// 取得本地主機名稱
// 初始化
WSADATA wsaData;if(WSAStartup(MAKEWORD(2,2), &wsaData)!= 0){
exit(0);}
// 通過主機名得到地址信息
printf(“ Get IP::”);gets(szMessage);
// 獲取主機信息
hostent *pHost = ::gethostbyname(szMessage);
// 打印出所有IP地址
in_addr addr;for(int i = 0;;i++){
char *p = pHost->h_addr_list[i];
if(p == NULL)
break;
memcpy(&addr.S_un.S_addr, p, pHost->h_length);
char *szIp = ::inet_ntoa(addr);
printf(“ 服務器 %s IP地址:%s n ”,szMessage, szIp);
printf(“服務器名字: %s n”,pHost->h_name);}
/////////////////////////// ::WSACleanup();
}
第2題代碼:
// 獲取并輸出本地主機的所有適配器的IP地址,子網掩碼,默認網關,MAC地址
#include
void main(){ // 定義變量
IP_ADAPTER_INFO *pAdapterInfo;ULONG ulOutBufLen;DWORD dwRetVal;PIP_ADAPTER_INFO pAdapter;
pAdapterInfo =(IP_ADAPTER_INFO *)malloc(sizeof(IP_ADAPTER_INFO));ulOutBufLen = sizeof(IP_ADAPTER_INFO);// 第一次獲取適配器信息,得到ulOutBufLen的實際大小
if(GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)!= ERROR_SUCCESS){
free(pAdapterInfo);
pAdapterInfo =(IP_ADAPTER_INFO *)malloc(ulOutBufLen);} // 第二次獲取適配器信息,獲得了pAdapterInfo信息
if(dwRetVal = GetAdaptersInfo(pAdapterInfo, &ulOutBufLen)!= ERROR_SUCCESS){
cout<<“GetAdapterInfo Error!”< // 打印MAC地址信息、子網掩碼以及網關 pAdapter = pAdapterInfo;while(pAdapter){ cout<<“MAC Address: ”; for(int i=0;i AddressLength;i++) { if(i ==(pAdapter->AddressLength-1)) { cout< } else { cout< } } cout< cout<<“IP 地址:”< IpAddressList.IpAddress.String< cout<<“子網掩碼 :”< IpAddressList.IpMask.String< cout<<“網關 :”< IpAddressList.IpAddress.String< cout<<“****************************************”< pAdapter = pAdapter->Next;} // 釋放資源 if(pAdapterInfo){ free(pAdapterInfo);} cout< } 實驗報告一、二、三、四、五、六、七、實驗名稱:分析PL0詞法分析程序 試驗目的 ? 學習PL0程序的詞法分析程序GenSym的實現過程 ? 結合具體的程序了解詞法分析過程 實驗設備 ? PC兼容機 ? DOS操作系統或Windows操作系統 ? TurboPascal軟件等 實驗要求 ? 獨立完程序的分析過程 ? 自己跟蹤程序的執行過程 ? 記錄程序的執行過程 ? 記錄程序的運行結果 實驗內容 實驗過程記錄 源程序 實驗動物學實驗報告 一、實驗動物:小鼠 二、操作流程:抓取,固定,編號,給藥,取血,麻醉,絕育,解剖。 三、具體操作 1、抓取:抓取小鼠時,右手抓住小鼠尾巴,不要過于用力,以免驚嚇小鼠。左手從小鼠身體后部向前抓(以免小鼠向后縮咬傷自己),抓住小鼠頸部。固定住小鼠后,將小鼠皮膚往上抓,盡量將小鼠背部皮膚抓住。左手將小鼠腹部朝向自己,把小鼠尾巴用左手無名指和小指夾住,這時小鼠腹部皮膚緊繃,不能動彈。 2、固定: 通常使用固定器進行固定。將固定器擰開后,抓住小鼠尾巴,使其鉆入固定器中,再將擰下的固定器部分裝好,使小鼠尾部露出,再將可旋轉的鐵片固定住即可進行后續實驗。 3、編號:編號方式有兩種:①剪腳趾編號:把小鼠腹面朝上,在下的腳趾從左至右依次編為1~10號,剪10號腳趾加1~9號腳趾依次編為11~19號,在上的腳趾依次編為20,30,40,50,60,70,80,90號,其余編號與11~19號類似。②打耳釘編號:耳釘上均有唯一編號,通過使用耳釘鉗將耳釘打在小鼠耳朵上即可。實驗時通常使用的是第一種方式進行編號,第二種編號通常用于需要長距離運輸的動物。 4、給藥:常用的給藥方式有: ①口服給藥:即灌胃。將注射器裝入藥物溶液,裝上灌胃針(灌胃針有直頭和彎頭兩種,區別不大)。如上所述,抓取小鼠后,使其頭部朝上,盡量呈一直線,取灌胃針,從小鼠嘴角一側緩緩插入(保持刻度在自己能看到的位置),順著小鼠口腔食道的弧度讓小鼠將針咽入,灌胃過程中如果遇到阻礙一定要及時拔出灌胃針,不可強行灌胃以免傷及小鼠食道以及肺部。灌胃針順利進入后基本與小鼠身體呈一條直線,注入適量體積后再順著食道緩緩取出灌胃針。 ②靜脈注射:小鼠尾部有3條靜脈和1條動脈,3條靜脈非別位于背部,及兩側。靜脈注射時一般選取兩側靜脈,因為其相對于背部靜脈更為清晰飽滿。將小鼠固定后,用酒精擦拭其尾部靜脈,使其充血,以便注射。之后使注射器針孔處朝上,針與尾部呈約30°扎入尾部后向上輕挑,再向內扎入部分,此過程應該比較順暢,沒有阻礙,若阻礙較大則有可能扎入到了皮膚中。扎入后將活塞向后回抽一點可見到有血回流,則說明成功扎入靜脈當中,注射適當體積后迅速拔針,用酒精進行消毒。 5、取血:有斷尾取血法和眼眶取血法兩種。本次實驗使用的是眼眶取血法。抓取小鼠,固定其頭部用手指將其上下眼瞼分開,露出其眼球并且不能閉上。用玻璃毛細管從其上眼角處扎入眼球后方毛細血管從,使血液順著毛細管留下,取血完成后快速將毛細管取下。 6、麻醉:抓取老鼠,使其頭部朝下,使其腹部臟器向胸腔靠攏,露出腹部空腔,以免刺傷臟器。將注射器豎直扎入靠近后腿部腹腔,刺入之后稍微向前傾斜但不要向前刺入,一般注入0.5mL麻醉劑即可。隨后拔出針,方向小鼠,等待幾分鐘后即可麻醉。 7、絕育:絕育手術是通過剪除雌鼠卵巢或雄鼠輸精管來實現的。將麻醉的雌鼠背面朝上,從其胸腔和尾部之間向下三分之一處剪開一個小口,用鑷子將其卵巢取出,上面呈現紅色斑點的部分即為卵巢,用剪刀將這一部分剪除,然后用縫合針線將其縫合,縫合方法為將針穿過后,將線纏繞鑷子兩圈再逆時針纏繞兩圈,再重復纏繞一遍,將鑷子夾住線頭把纏繞的線移至線頭系緊即可(縫合過程全程用鑷子和剪刀操作),里面肌肉層以及外面皮層均需縫合。雄鼠則從外生殖器向上1-2cm處剪開小口,用鑷子在其中找出輸精管(較細長的乳白色小管),盡量多減掉一些,以免其長長愈合,以上述方法縫合傷口即可。 9、解剖:以頸椎脫臼法處死小鼠,使其腹面朝上。用鑷子將其腹部皮膚夾起,然后用剪刀剪開,觀察各個器官所在位置和形態,解剖完的小鼠放入尸體袋中。第四篇:實驗報告格式--實驗2
第五篇:實驗動物學實驗報告