第一篇: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.xiexiebang.com对应的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
第五篇:实验动物学实验报告