计算机网络与TCPIP协议体系2.docx
《计算机网络与TCPIP协议体系2.docx》由会员分享,可在线阅读,更多相关《计算机网络与TCPIP协议体系2.docx(16页珍藏版)》请在冰豆网上搜索。
计算机网络与TCPIP协议体系2
本科生实验报告
实验课程计算机网络与TCP/IP协议体系
(2)
学院名称信息科学与技术学院
专业名称
学生姓名
学生学号
指导教师
实验地点6B603
实验成绩
二〇一五年二月——二〇一五年六月
实验一Linux内核通用链表的使用
1、实验目的
学习Linux内核通用链表的设计原理,熟练掌握Linux内核通用链表的使用。
2、实验内容
1、掌握Linux通用链表的创建
2、掌握通用链表添加元素、删除元素和遍历链表的方法
3、掌握通用链表的查找方法
3、实验要求
待创建的链表头变量名为user_queue。
作为链表的宿主节点类型定义如下:
structuser{
intid;/*userid*/
structlist_headlist;
};
针对上述user_queue链表,要求以队列方式向其中依次添加10个类型为structuser的宿主节点,并要求这10个宿主节点的id依次为1—10
依次遍历输出这10个宿主节点的id
从链表中删除首个宿主节点,然后依次遍历该队列并输出余下各宿主节点的id
在structuser结构体中增加一个username字段,用于存储该用户名字,重新以队列方式向其中依次添加10个类型为structuser的宿主节点,并要求这10个宿主节点的id依次为1—10
在链表中搜索id值为5的节点,并输出该节点username值
实现代码和运行结果
#include
#include
#include"list.h"
structuser{
intid;
structlist_headlist;
};
intmain()
{
LIST_HEAD(user_queue);
structuseru[10];
structuser*p;
inti;
for(i=0;i<10;i++)
{
list_add_tail(&u[i].list,&user_queue);
u[i].id=i+1;
}
list_for_each_entry(p,&user_queue,list)
printf("userid%d\n",p->id);
return0;
}
2.#include
#include
#include"list.h"
structuser{
intid;
structlist_headlist;
};
intmain()
{
LIST_HEAD(user_queue);
structuseru[10];
structuser*p,*pdel;
inti;
for(i=0;i<10;i++)
{
list_add_tail(&u[i].list,&user_queue);
u[i].id=i+1;
}
pdel=&(u[0]);
list_del(&(pdel->list));
list_for_each_entry(p,&user_queue,list)
printf("userid%d\n",p->id);
return0;
}
3.#include
#include
#include
#include"list.h"
structuser{
intid;
charname[8];
structlist_headlist;
};
intmain()
{
LIST_HEAD(user_queue);
structuseru[10];
structuser*p;
inti;
for(i=0;i<10;i++)
{
list_add_tail(&u[i].list,&user_queue);
u[i].id=i+1;
printf("inputusername:
\n");
scanf("%s",u[i].name);
}
list_for_each_entry(p,&user_queue,list)
printf("userid%d,username%s\n",p->id,p->name);
printf("searchid:
\n");
inta;
structuser*pa;
scanf("%d",&a);
pa=&(u[a]);
printf("nameis%s\n",pa->name);
return0;
}
实验二Linux内核通用哈希链表的使用
1、实验目的
学习Linux内核通用哈希链表的设计原理,熟练掌握Linux内核通用哈希链表的使用。
2、实验内容
1、掌握Linux通用哈希链表的创建。
2、掌握通用哈希链表添加元素、查找元素的方法。
3、实验要求
1、待创建的哈希链表头数组为structhlist_headuser_hash[16],要求对该structusermap...structusermapstructhlist_node
哈希链表宿主节点
的name成员值进行散列,并将散列值与15进行与运算作为哈希链表宿主元素的哈希值。
2、对该哈希表的所有表头元素进行初始化,初始化操作如下,其中index的变化范围为0~15。
INIT_HLIST_HEAD(&user_hash[index]);
3、作为哈希链表元素的的宿主节点类型定义如下:
structusermap{
structhlist_nodehlist;
unsignedcharname[8];
};
4、针对上述user_hash哈希链表,要求向其中添加3个类型为structusermap的宿主节点,并要求这3个宿主节点的name成员分别为”smith”,”john”,”bob”,如下图所示:
5、向哈希表user_hash中添加2个新宿主元素,其中一个宿主元素的name成员为”john”,另外一个宿主元素的name成员为”lisa”。
要求若新宿主元素的name成员已经存在,则提示已经存在该用户,不再向哈希链表中加入该已经存在的宿主节点,否则向哈希链表中添加该新宿主元素。
6、遍历整个哈希表,输出所有表中已存在的宿主节点元素的name。
4、实现代码和运行结果
#include
#include
#include"list.h"
structusermap{
structhlist_nodehlist;
unsignedcharname[8];
};
voidhlist_print(structhlist_head*hl_head);
unsignedintBKDRHash(unsignedchar*str);
unsignedcharhash_add(structhlist_node*hl_node,structhlist_head*hl_head);
intmain(void)
{
structhlist_headuser_hash[16];
for(inti=0;i<16;i++)
INIT_HLIST_HEAD(&user_hash[i]);
structusermapuser[3];
strcpy(user[0].name,"smith");
strcpy(user[1].name,"john");
strcpy(user[2].name,"bob");
for(inti=0;i<3;i++)
hlist_add_head(&(user[i].hlist),&user_hash[BKDRHash(user[i].name)&15]);
hlist_print(user_hash);
structusermapnew_user[2];
strcpy(new_user[0].name,"john");
strcpy(new_user[1].name,"lisa");
for(inti=0;i<2;i++)
if(!
hash_add(&(new_user[i].hlist),&user_hash[BKDRHash(new_user[i].name)&15]))
printf("用户%s重复,添加失败!
\n",new_user[i].name);
hlist_print(user_hash);
return0;
}
voidhlist_print(structhlist_head*hl_head)
{
structusermap*puser;
structhlist_node*phnode;
for(inti=0;i<16;i++)
{
printf("%d\t",i);
hlist_for_each_entry(puser,phnode,&hl_head[i],hlist)
printf("%s\t",puser->name);
printf("\n");
}
}
unsignedintBKDRHash(unsignedchar*str)
{
unsignedintseed=131;
unsignedinthash=0;
while(*str){
hash=hash*seed+(*str++);
}
return(hash&0x7FFFFFFF);
}
unsignedcharhash_add(structhlist_node*hl_node,structhlist_head*hl_head)
{
char*name=hlist_entry(hl_node,structusermap,hlist)->name;
structusermap*puser;
structhlist_node*pnode;
hlist_for_each_entry(puser,pnode,hl_head,hlist)
{
if(!
strcmp(puser->name,name))
return0;
}
hlist_add_head(hl_node,hl_head);
return1;
}
实验三Linux多线程程序设计
1、实验目的
学习Linux下多线程程序的编写,掌握IP报文分段重组模拟程序的整体框架。
2、实验内容
完成Linux下多线程的程序编写,利用线程同步的方法,完成多线程访问一个由Linux内核通用链表所实现的消息队列。
3、实验要求
待创建的消息队列名为msg_queue。
作为消息队列的消息宿主节点类型定义如下:
structmsg_buff{
intid;
structlist_headlist;
};
针对上述msg_queue队列,要求创建两个线程1和线程2,其中线程1向该队列尾逐步添加10个类型为structmsg_buff的宿主节点,并要求者10个宿主节点的id分别为1—10。
另外,在线程1向该队列添加宿主节点的同时,要求线程2从该队列头部依次取出下一个宿主节点,并输出该节点的id值。
4、实现代码和运行结果
#include
#include
#include
#include
#include"list.h"
#definePAUSE3000
void*run(void*);/*消息处理线程*/
voidadd_msg(int);
structmsg_buff*getnextmsg(structlist_head*);
voidhandle_msg(structmsg_buff*);
structmsg_buff{
intid;
structlist_headlist;
};
/*线程互斥量*/
pthread_mutex_tmqlock=PTHREAD_MUTEX_INITIALIZER;
/*条件变量*/
pthread_cond_tmqlock_ready=PTHREAD_COND_INITIALIZER;
pthread_ttid;/*消息处理线程id*/
LIST_HEAD(msg_queue);/*消息队列*/
intmain()
{
interr=0;
err=pthread_create(&tid,NULL,run,NULL);/*创建并启动消息处理线程*/
for(inti=0;i<10;i++){
add_msg(i);/*向消息队列添加消息*/
sleep
(1);
}
return0;
}
voidadd_msg(inti)
{
//完成向队列添加消息代码
structmsg_buff*new_msg=(structmsg_buff*)malloc(sizeof(structmsg_buff));
new_msg->id=i;
pthread_mutex_lock(&mqlock);
list_add_tail(&new_msg->list,&msg_queue);
pthread_mutex_unlock(&mqlock);
pthread_cond_signal(&mqlock_ready);
}
void*run(void*arg)
{
structmsg_buff*msg;
for(;;){
//通过getnextmsg函数从队列中取下一消息
pthread_mutex_lock(&mqlock);
while(list_empty(&msg_queue))
pthread_cond_wait(&mqlock_ready,&mqlock);
msg=getnextmsg(&msg_queue);
pthread_mutex_unlock(&mqlock);
handle_msg(msg);/*处理消息*/
free(msg);
}
}
structmsg_buff*getnextmsg(structlist_head*q)
{
structmsg_buff*msg;
//完成从队列中取下一消息代码
msg=list_first_entry(q,structmsg_buff,list);
list_del(&msg->list);
returnmsg;
}
voidhandle_msg(structmsg_buff*m)
{
printf("m->id=%d\n",m->id);/*处理此分组*/
}
实验四IP报文分段重组模拟
1、实验目的
学习Linux内核IP报文分段和重组的原理,掌握IP报文分段重组模拟程序的关键实现方法。
2、实验内容
1、联调Forward而和Host程序,观察基于消息分段和重组的文件传输过程。
2、完成IP报文分段和重组程序中用户退出登录的功能实现。
3、实验要求
1、选定4台PC工作站,其中一台作为转发服务器Forwarder,两台作为文件传输的发送方Host,另外一台作为接收方Host。
2、每3人一组,参考教材《网络编程与分层协议设计—基于Linux平台实现》第9.10一节的说明,完成IP报文分段与重组模拟程序的编译,并将Forwarder和Host正确部署在上述4台工作站上,以实现不同Host之间的文件传输。
3、仔细阅读Host.c和Forwarder.c源文件中关于消息分段、再分段和分段重组函数的实现代码。
完成Host.c中app_do_exit函数的实现,要求当某个已登录Host退出后,其他仍在线用户的的在线用户列表中能去除该退出登录的用户名。
4、实验任务
(1)实现退出登录业务功能
请完成某个登录用户退出的功能实现,要求所有其他在线用户通过刷新用户登录列表,可以看到该退出登录用户已经下线。
(2)程序运行截图
5、实现代码和运行结果
intapp_
do_exit(structmsg_buff*p_mbuf,structapp_hdr*ah)
{structlist_head*pos;
structlogin_exit*p_exit;
structusermap*p_usrmap;
unsignedinthash;
structhlist_node*n;
charwho[NAMESIZE],ch;
charusers[HQ_HASHSZ];
intuser_no;
u8*where;
u32user_ip;
u32who_ip;
intFOUND=0;
intnum=1;
memset(users,0,HQ_HASHSZ);
where=users;
p_exit=(structlogin_exit*)ah;
pthread_mutex_lock(&usrlock);
if(more)goto
shortcut;
memcpy(who,p_exit->user,NAMESIZE);
hash=BKDRHash(who)&(HQ_HASHSZ1);
hlist_for_each_entry(p_usrmap,n,&user_hash[hash],hlist)
if(!
strcmp(p_usrmap->name,who))
{printf("Toruntheapp_do_exit!
\n");
list_move(&p_usrmap->list,&user_queue);
list_del(&p_usrmap->list);
hlist_del(&p_usrmap->hlist);}elsegotoout;shortcut:
printf("[0]MORE");
list_for_each(pos,&user_queue)
{p_usrmap=list_entry(pos,USERMAP,list);
memcpy(where,p_usrmap->name,NAMESIZE);
where+=NAMESIZE;
printf("[%d]%s",(++num)-1,p_usrmap->name);
}
pthread_mutex_unlock(&usrlock);
if(num)
{do{printf("\nChooseoneusertobeginFragmentation""exercise:
");
scanf("%d",&user_no);
while((ch=getchar())!
='\n');
if(user_no==0)
{gotoout;}
if(user_no>0&&user_no<=num-1)
break;}
while(user_no>num-1);
memcpy(who,users+NAMESIZE*(user_no-1),NAMESIZE);
who_ip=ip_find(who);
send_file(who_ip);
}out:
return0;
}
学生实验心得
通过实验课自己动手写代码、运行、检查错误,因此加深了对上课学习的内容的理解,明白了在学习的过程中,遇到不懂的要自己去搜索资料,不断思考,不断总结。
学会了一些简单的程序操作,比如通用链表和哈希链表的创建、添加、删除节点及遍历操作。
在实验一和实验二中了解到了内核链表和哈希链表之间的不同,在哈希链表中用了二级指针
,还有IP报文的分段与重组原理,在此实验中了解到了MTU的重要性。
学生(签名):
2015年6月18日
指导
教师
评语
成绩评定:
指导教师(签名):
年月日