苏州科技学院
电子信息实验中心
实验报告
课
程 学
号 姓
名 班
级 专
业 指导教师 学年 / 学期
计算机网络原理 13200126132 闫自立 软件1311 计算机科学与技术
陶滔
2015~2016学年第1学期
实验三
网络层实验
实验项目性质:设计性
计划学时:4 实
验 环 境:Microsoft Visual Studio 2010
实验日期:2015年12月2日
一、实验目的
1.理解通信子网的完整概念,掌握网络层的作用和功能。 2.掌握分组数据包格式设计方法、分组的分片与重装的方法。 3.掌握网络层简单路由选择协议的实现方法。
二、实验内容
在已经实现的数据链路层基础上:
(1) 设计简易实用的分组数据包格式;
(2) 设计并实现类IP的网络层协议,路由选择采用静态路选择协议。 (3) 设计并实现分组的分片与重装。
(4) 设计一个应用程序,利用网络层的功能直接将文件传输到目标主机的接收窗口中。 (5) 编写路由配置route_tab.cfg及本机主机地址local.cfg文件,以便与远地的其他计算机进行通信。
三、实验(设计)仪器设备和材料清单
计算机一台,串行电缆一根。
四、实验指导
本实验采用静态路由选择算法,每个结点上通过配置文件route_tab.cfg确定路由选择的结果,该文件的格式可设计如下:
主机地址
端口号
注释
555
#主机地址555的转发端口号为COM1
556
558
888
*
#默认路由
其中,端口号指PC的COM1(对应端口号1)或COM2(对应端口号2)等。同时为简化设计,去掉流量控制和拥塞控制,数据包的格式参考IP数据包格式,但尽可能简化。
1 分组及其他数据结构设计
网络层的分组设计一方面要考虑到路由选择的实现,即分组中应含有路由寻址所必要的信息,另一方面要考虑到分组太大时的分片与重装,主机地址用4位数字字符表示。设计的分组格式如下。
(1) 分组(“数据报”)的首部
typedef struct{ //定义数据报首部格式
unsigned char
vers_hlen;
//高4位是版本, 低4 位是首部长度
1
unsigned char
type;
//类型(保留)
unsigned short
Dlen;
//数据报数据部分长度
unsigned short ident;
//数据报标识
unsigned short frag;
//分片标识,1-分片,0-不分片 unsigned short offset;
//数据报分片偏移量
unsigned char
TTL;
//生存期
unsigned char
prot[3];
//保留
unsigned short checksum;
//校验和
IPhost source;
//源主机地址
IPhost dest;
//目标主机地址
} TIPheader ; typedef struct { unsigned char cAddr[4];}IPhost; (2) 数据报格式
typedef struct { unsigned char cData[MTU];} Msg; typedef struct{
//定义数据报格式
TIPheader
IpHdr;
//分组首部
Msg
Info;
//分组信息部分 } TPacket; (3) 分片与重装的结构
typedef struct fid{
//用于识别同一IP 分组的各分片结构,用于组装分组
IPhost
source;
//源主机地址
IPhost
dest;
//目标主机地址
unsigned short
ident;
//IP分组标识
long int iLength;
//已接收到的数据长度
unsigned short iCount; //已接收到的分组数 }FragId; typedef struct fragif{
//包含一个分片的结构
unsigned char frgData[MTU]; //分片的数据部分
unsigned short iMsgLength;
//当前分片数据部分的长度 unsigned short frag;
//分片标识,1-分片,0-不分片
unsigned short offset;
//分片在数据报中的偏移量
struct fragif *next;
//下一个分片 }FragInfo; (4) 路由表结构
typedef struct { //定义路由表
unsigned char cHostAddr[4]; //主机地址 char cPort;
//转发端口
char cComment[30];
//注释 } TRouteItem; 2 分片与重装
在一个异构的网络的集合中,提供统一的主机到主机服务模型需要面对的问题之一是每种网络技术都试图自己定义分组的大小。例如,以太网能接收的长度最多为1500字节的分组,而FDDI能够接收的分组长度可达到4500字节。因此网络层要确保所有的分组足够小,使得其适合任何网络技术的分组;或者当分组对某一网络技术来说太大时,提供一种方法将分组拆分和重组。后一种方法是一种理想的选择,TCP/IP中的IP数据报传输就采用了后一种技术。
这样每一种网络类型有一个最大传输单元(Maximum Transmiion Unit,MTU),这是一帧中所能携带的最大数据报,而这个值应比网络上的最大分组要小。
五、结果分析(可根据需要附加页)
2
3
六、主要源代码(可根据需要附加页) #pragma hdrstop #include #include
#include \"..\\include\\NllEntity.h\" #include \"..\\include\\FtpCla.h\" //------------- #pragma package(smart_init) //--------- void TNLLNetEntity::readroute() {
#define MAXITEMS 100
// 路由表最大表项数
#define MAXLINE 81
// 路由表文件最大行长度
char fileName[]=\".\\route_tab.cfg\";
if(fst.fail()) return; fst.getline(line,MAXLINE); while(!fst.fail()&&!fst.eof()) // 当文件有内容时 {
} iRouteEntries=i; if(iRouteEntries) {
routeTab=new TRouteItem[iRouteEntries]; for(i=0;i
} fst.getline(line,MAXLINE); istrstream is(fstr); is>>route[i].cHostAddr>>route[i].cPort; i++; fstream fst(fileName, ios::in); int i=0; char line[MAXLINE], *fstr; TRouteItem route[MAXITEMS];
// 只读方式打开指定文件,建立文件流对象
fstr++;
4 }
#undef MAXLINE
#undef MAXITEMS } //--------- void TNLLNetEntity::setDll(TDLLNetEntity *dll, int nport) {
m_Dll[nport]=dll; } //--------- void TNLLNetEntity::purgeroute() {
delete routeTab;
iRouteEntries=0; } //--------- void TNLLNetEntity::makePacket(TPacket &pkt,TIPheader &hdr,unsigned char *buf, int len) {
memcpy(&pkt.IpHdr,&hdr,sizeof(TIPheader));
memcpy(&pkt.Info,buf,len); } //--------- void TNLLNetEntity::sendPacket(TPacket & pkt) {
unsigned char
*ptr;
int len=pkt.IpHdr.Dlen+sizeof(TIPheader);
unsigned char
*buf=new unsigned char[len];
ptr=buf;
memcpy(ptr,&pkt.IpHdr,sizeof(TIPheader));ptr=ptr+sizeof(TIPheader);
memcpy(ptr,&pkt.Info,pkt.IpHdr.Dlen);
int n_port;
unsigned char q[4];
memcpy(q,&pkt.IpHdr.dest,4);
n_port=findroute(pkt.IpHdr.dest);
if (n_port==-1)/不到指定路由
//查找默认路由
{
IPhost dest;
memset(&dest,0,4);
memcpy(&dest,\"*\",1);
n_port=findroute(dest);
if (n_port==-1)//如不存在,丢弃
return;
5
}
if (n_port>MAX_PORTS)
return;
//成帧
Frame frm;
frm.info=new unsigned char[len];
m_Dll[n_port]->makeDataframe(frm,buf,len);
//发送帧
m_Dll[n_port]->SendFrame(frm);
delete buf; } //--------- void TNLLNetEntity::senddata(unsigned char
*cPinfo,IPhost &dest,int len) { //make header
TPacket pkt;
TIPheader phdr;
unsigned char *cPtr;
unsigned short
len1,offset;
cPtr=cPinfo;
//设置数据报首部,以部分各个分片相同
phdr.vers_hlen=IPVERS;
phdr.vers_hlen=phdr.vers_hlen|sizeof(TIPheader);
memcpy(&phdr.source,&localaddr,sizeof(IPhost));
memcpy(&phdr.dest,&dest,sizeof(IPhost));
phdr.type=0xe;
phdr.TTL=0xf; //
phdr.prot=0;
phdr.ident=iIdentify++;
//设置下一个数据包的标识
if (iIdentify==0xFFFF) iIdentify=1;
len1=len;
offset=0;
while
(len1>0)
{
if (len1>MTU){
//需要分片?
phdr.Dlen=MTU;
phdr.frag=1;
//分片标志
phdr.offset=offset; //
phdr.chksum=makechksum(phdr); //产生校验
makePacket(pkt,phdr,cPtr, MTU);
6
cPtr+=MTU;
offset+=MTU;
len1=len1-phdr.Dlen;
}
else{
//不再需要分片
phdr.Dlen=len1;
phdr.frag=0;
//分片结束标志
phdr.offset=offset;
makePacket(pkt,phdr,cPtr, len1);
len1=0;
}
sendPacket(pkt);
}//end while }
//发送当前分组 7