1、 计算机网络原理课程实验指导书 《计算机网络原理》实验指导书 目 录 《计算机网络原理》实验指导书 1 实验一 IP协议分析 2 一、实验目的 2 二、实验学时 2 三、实验类型 2 四、实验步骤 2 实验二 TCP网络编程 5 一、实验目的 5 二、实验学时 5 三、实验类型 5 四、实验步骤 5 实验一 IP协议分析 一、实验目的 1. 掌握IP数据报的报文格式 2. 掌握子网掩码和路由转发 二、实验学时 4学时 三、实验类型 验证型实验 四、实验步骤 实验分组进行,每组6人,采用网络结构二。
2、 说明:主机A、C、D的默认网关是172.16.1.1;主机E、F的默认网关是172.16.0.1。 主机B启动静态路由服务(方法:在命令行方式下,输入“staticroute_config”)。 按照拓扑结构图连接网络,使用拓扑验证检查连接的正确性。 练习一:领略真实的ARP(同一子网) 1. 主机A、B、C、D、E、F在命令行下运行“arp -a”命令,察看ARP高速缓存表。 【问题】 l ARP高速缓存表由哪几项组成? 2. 主机A、B、C、D启动协议分析器,打开捕获窗口进行数据捕获并设置过滤条件(提取ARP、ICMP)。 3. 主机A、B、C、D在命令行下运行“ar
3、p -d”命令,清空ARP高速缓存。 4. 主机A ping 主机D(172.16.1.4)。 5. 主机A、B、C、D停止捕获数据,并立即在命令行下运行“arp -a”命令察看ARP高速缓存。 【问题】 结合协议分析器上采集到的ARP报文和ARP高速缓存表中新增加的条目,简述ARP协议的报文交互过程以及ARP高速缓存表的更新过程。 练习二:编辑并发送IP数据报 1. 主机A启动仿真编辑器,编辑一个IP数据报,其中: MAC层: 目的MAC地址:主机B的MAC地址(对应于172.16.1.1接口的MAC)。 源MAC地址:主机A的MAC地址。
4、 协议类型或数据长度:0800。 IP层: 总长度:IP层长度。 生存时间:128。 源IP地址:主机A的IP地址(172.16.1.2)。 目的IP地址:主机E的IP地址(172.16.0.2)。 校验和:在其它所有字段填充完毕后计算并填充。 【问题】 l IP在计算校验和时包括哪些内容? 2. 在主机B(两块网卡分别打开两个捕获窗口)、E上启动协议分析器,设置过滤条件(提取IP协议),开始捕获数据。 3. 主机A发送第1步中编辑好的报文。 4. 主机B、E停止捕获数据,在捕获到的数据中查找主机A所发送的数
5、据报。 【问题】 l 第1步中主机A所编辑的报文,经过主机B到达主机E后,报文数据是否发生变化?若发生变化,记录变化的字段,并简述发生变化的原因。 5. 将第2步中主机A所编辑的报文的“生存时间”设置为1。重新计算校验和。 6. 主机B、E重新开始捕获数据。 7. 主机A发送第5步中编辑好的报文。 8. 主机B、E停止捕获数据,在捕获到的数据中查找主机A所发送的数据报。 【问题】 l 主机B、E是否能捕获到主机A所发送的报文?简述产生这种现象的原因。 实验二 TCP网络编程 一、实验目的 1. 了解基于MFC的TCP网络编程的方式 2. 学习使用MFC编写简单的
6、TCP网络程序 二、实验学时 4学时 三、实验类型 设计型实验 四、实验步骤 该实验以两位同学为一组,一位同学开发服务器程序,一位同学开发客户端程序。使得客户端与服务器之间能够实现信息交换。 一、Windows Socket和套接口的基本概念 网际协议(Internet Protocol,IP)是一种用于互联网的网络协议,已广为人知。它可广泛用于大多数计算机操作系统上,也可用于大多数局域网LAN(比如办公室小型网络)和广域网WAN(比如说互联网)。从它的设计看来,它是一个无连接的协议,并不能保证数据投递万无一失。两个上层协议(TCP和UDP)依赖IP协议进行数据通信
7、 如果希望在Microsoft Windows下经过TCP和UDP协议建立网络应用程序,则需要使用Winsock套接口编程技术。 套接口,就是一个指向传输提供者的句柄。Win32中,套接口不同于文件描述符,因此它是一个独立的类型——SOCKET。Windows Sockets描述定义了一个Microsoft Windows的网络编程界面,它是从Unix Socket的基础上发展而来的,为Windows TCP/IP提供了一个BSD型的套接字规范,除与4.3BSD Unix Sockets完全兼容外,还包括一个扩充文件,经过一组附加的API实现Windows式(即事件驱动)的编程风格;而W
8、insock则是在Microsoft Windows中进行网络应用程序设计的接口。Windows在Internet支配域中的TCP/IP协议定义了Winsock网络编程规范,融入了许多新特点。使用Socket的目的是使用户在网络协议上工作而不必对该网络协议有非常深入的了解。另外,编写的程序还可被迅速地移植到任何支持Socket的网络系统中去。 Winsock提供了二种可为指定传输协议打开、计算和关闭会话的能力。在Windows下,TCP/IP上层模型在很大程度上与用户的Winsock应用有关:换言之,用户的Winsock应用控制了会话的方方面面,必要时,还会根据程序的需要格式化数据。
9、 套接口有三种类型:流式套接口、数据报套接口及原始套接口。 流式套接口定义了一种可靠的面向连接的服务(利用TCP协议),实现了无差错无重复的顺序数据传输。数据报套接口定义了一种无连接的服务(UDP协议),数据经过相互独立的报文进行传输,是无序的,而且不保证可靠和无差错。原始套接口允许对低层协议如IP或ICMP直接访问,主要用于新的网络协议实现的测试等。 面向连接服务器处理的请求往往比较复杂,不是一来一去的请求应答所能解决的,而且 往往是并发服务器。使用面向连接的套接口编程,能够经过图来表示。 无连接服务器一般都是面向事务处理的,一个请求、一个应答就完成了客
10、户程序与服务程序之间的相互作用。若使用无连接的套接口编程,程序的流程能够用图表示。 套接口工作过程如下:服务器首先启动,经过调用socket()建立一个套接口,然后调用bind()将该套接口和本地网络地址联系在一起,再调用listen()使套接口做好侦听的准备,并规定它的请求队列的长度,之后,调用accept()来接收连接。客户在建立套接口后就可调用connect()和服务器建立连接。连接一旦建立,客户机和服务器之间就能够经过调用read()和write()来发送和接收数据。最后,待数据传送结束后,双方调用close()关闭套接口。 在网络编程中,掌握端口的概念十分重要
11、 端口:基于TCP/IP协议的网络中,计算机都分配有一个IP地址,用一个32位二进制数来表示,正式的称呼是“Ipv4地址”。客户机需要经过TCP或UDP和服务器通信时,必须指定服务器的IP,地址和服务端口号。另外,服务器打算侦听接入客户机请求时,也必须指定一个IP,地址和一个端口号。在选择端口时,应特别小心,因为有些可用端口号是为“已知的”(即固定的)服务保留的,如文件传输协议和超文本传输协议,即FTP(21号端口)和HTTP(一般为8080端口)。“已知的协议”,即固定协议,采用的端口由“互联网编号分配认证(IANA)”控制和分配,RFC 1700中说明的编号。 从本质
12、上说,端口号可分成3类:“已知”端口、已注册端口、动态和(或)私用端口。 (1)“已知”端口0-1023,由IANA控制,是在UNIX中为固定服务保留的。 (2)已注册的端口1024-49151,由IANA列出来的,供普通用户的普通用户进程或程序使用。 (3)动态和(或)私用端口49152-65535。 普通用户应用应选择1024-49151之间的已注册端口,从而避免端口号已被另一个应用或系统服务所用。另外,49152-65535间的端口可自由使用,因为IANA这些端口上没有注册服务。 二、MFC CSocket类的通信流程 使用CSockct类进行
13、网络二进制数据通信的连接流程,如下表所示。 服务器端 注释 客 户 端 l Csocket m_server 构造一个socket对象 Csocket m_client 2 m_server.create(nport) 创立socket M_client.create(nport) 3 m_server.listen() 听等 连接 与服务器 建立连接 m_client.connectstraddr,nport) 此时阻塞。等待服务器端侦听。 4 Csocket m_receive;
14、 m_server.accpet(m_receive) 此时阻塞,等待客户机连接. 构造新的socket对象用以接收 客户端的连接 5 CsocketFile file(&m_server); 构造一文件对象 CsocketFile file(&m_server) 6 CArchive arin(&file,CArchive::load) CArchive arout(&file,CArchive::store) 构造流对象 CArchive arin(&file,CArchive::Ioad) CArchive
15、
arout(&file,CArchive::store)
7
arin>>value;
arout< 16、是:服务器首先启动,创立套接字后等待客户的连接;客户启动以后,创立套接字,然后和服务器建立连接;连接建立后,客户机和服务器能够经过建立的套接字连接进行信息通信。注意其中红色字体为LX1需做,黑色字体为LX2需做,蓝色字体表示二者都需做的部分。
先建立一个MFC,选DialogBased,工程名为Lx2,如图所示。
下一个对话框选择Window Sockets,后面的选项酌情考虑,或者连续选择默认的即可,如图所示。
如果忘了添加Windows Sockets选项,能够在文件头部添加下列语句进行补救:
#include “Winsock.h”
#inc 17、lude “ws2tcpip.h”
#pragma comment(1ib, “Ws2_32.lib”)
注:这些语句支持winsock2。
出现Dialog以后,编辑界面,使其如图所示而且对控件点击右键,选择属性选项,把每个控件的ID改掉(控件ID就是每个控件的名字,要改成有意义的,以便将来管理)。
各个控件的ID如下表,而且在对话框视图中点击右键,选择Class Wizard选项,用该工具对控件添加变量。
控件ID
变量名
绑定变量类型
对应界面上的控件
IDC_CONTENT
m_msg
CString
输入 18、发送内容的文本框
IDC_CONTENT
m_ctrl
CEdit
输入发送内容的文本框
IDC_LISTEN
m_listen
CButton
侦听按钮
IDC_SEND
re_send
CButton
发送按钮
接着,再打开一个VC,建立客户机工程,工程名称为Lx1,各个控件的ID如下表
控件ID
变量名
绑定变量类型
对应界面上的控件
IDC_CONTENT
m_msg
CStringt
输入发送内容的文本框
IDC_CONTENT
m_ctrl
CEdit
输入发送内容的文本框
IDC_CONNECT
m_ 19、connect
CButton
连接按钮
IDC_SEND
m_send
CButton
发送按钮
IDC_IP
m_lp
CString
输入连接目的IP的文本框
然后,在BOOL CLx1Dig::OnlnitDialog()和BOOL CLx2DIg::OnlnitDialog()末尾添加语句,使其如下所示:
m_send.EnableWindow(FALSE); //使发送按钮变灰
return TRUE; //return TRUE unless you
//set the focus 20、to a control
注意:这个语句作用使发送按钮失效,以免还未连接用户就点击发送,发生不可预计的错误。
为了在程序中更自由地处理CSocket得到的消息,必须新建CSocket的派生类:
在Lx2工程的工作区类视图中点击右键,添加新类: CServer,父类为CSocket。
NewClass对话框:
在lx2Dlg.h里添加:
头文件: #include “Server.h”
private变量: CServer m_server; CServer m_recv;
在对话框的图像上双击“侦听”按钮,添加如下代 21、码:
void CLx2Dlg::OnListen()
{
m_server.Create(1000); //使用1000号端口
m_server.Listen(); //侦听
}
在对话框图像上再双击“发送"按钮,添加如下代码:
void CLx2Dlg::OnSend()
{
UpdateData(TRUE); //更新数据,使m_msg得到当前框中文本
m_recv.Send(m_msg, 255); //发送数据
m 22、ctrl.SetSel(0, -1); //全选发送框文字
m_ctrl.ReplaceSel(“”, TRUE); //将发送框置空
}
同样地,在Lxl工程的工作区类视图中点击右键,添加新类:
CClient
它继承自CSocket。在CLxlDIg类里添加private变量:
CClient m_client;
双击对话框图像上的“连接”按钮,添加代码:
void CLxlDlg::OnConnect()
{
UpdateData(TURE);
m_client 23、Create(1001); //使用1001号端口
if(m_client.Connect(m_ip, 1000)) //连接目标地址,1000端口
{
AfxMessageBox(“Client端连接成功”);
m_send.EnableWindow(TRUE); //连接成功,能够发送
m_connect.EnableWindow(FALSE); //同时禁止连接按钮
}
else
{
24、 m_client.Close(); //如果连接失败就关闭
AfxMessageBox(“连接失败”);
}
}
双击发送按钮,添加代码:
void CLx1Dlg::OnSend()
{
UpdateData(TRUE); //更新数据,使m_msg得到当前框中文本
m_client.Send(m_msg, 255); //发送数据,长度255字节
m_ctrl.SetSel(0, -1); //全选发送框文字
m_ctrl.ReplaceSel(“”, TRUE); 25、 //将发送框置空
)
经过以上操作,我们建立了CSocket,主机、客户机建立连接后的消息发送代码也添加完成了,可是还缺少使其工作的消息机制。
下面的步骤就是利用OnAccept和OnReceive函数处理socket消息。
首先,在Lx2工程的编辑界面中点击右键,选Class Wizard,在classname栏目里面找到CServer类,添加OnAccept和OnReceive函数而且双击下面的Member function栏目,分别为两个函数添加如下代码:
void CServer::OnAccept(int nErrorCode)
26、{
//TODO: Add your specialized code here and/or call the base class
CSocket::OnAccept(nErrorCode);
((CLx2Dlg*)(AfxGetApp()->m_pMainWnd))->ShowAccept();
//这里仅仅添加了这一句,因为CLx2DIg类是发送接收消息的主窗口,
//而且应用程序发送接收的消息也在CLx2Dlg对象实例中进行,
//因此当CServer类的对象收到客户机的Con 27、nect消息时,
//便可调用CLx2DLg对象中的ShowAccept()函数处理。
}
该步完成以后,能够为CLx2DIg类添加public成员函数ShowAccept():
void CLx2Dlg::ShowAccept()
{
m_server.Accept(m_recv);
AfxMessageBox(“Server端连接成功”);
m_send.EnableWindow(TRUE); //连接成功,能够发送
m_listen.EnableWindow(FALSE); //同 28、时禁止侦听按钮
}
于是,当客户机调用m_client.Connect(m_ip,1000)时,主机server端发现并调用ShowAccept函数来建立连接。执行完以后,Socket连接便被建立。
接下来的工作便是添加发送聊天信息的函数了。
注意到前面点击发送按钮的OnSend()函数已经添加好了,在Lx2工程中只要添加Server
端的接收消息和显示消息功能就能够进行消息的传送。
在CServer类中像添加OnAccept()一样添加成员函数OnReceive():
void Cserver::OnReceive(int nErrorC 29、ode)
{
// TODO: Add your specialized code here and/or call the base class
CSoeket::OnReceive(nErrorCode);
((CLx2Dlg*)(AfxGetApp()->m_pMainWnd))->ShowMsg();
}
建立连接后,一方一旦发送数据,另一方的CSocket派生类便调用该函数。其中代码能够参考前面OnAccept()进行理解。
在CLx2DIg里添加成员函数ShowMsg():
void CLx 30、2Dlg::ShowMsg()
{
char buf[255];
m_recv.Receive(buf, 255); //接收消息到buf里面,长度255字节
CString msg;
Msg.Format(“%s”, buf);
AfxMessageBox(msg); //用AfxMessageBox函数显示接收到的字符串
//这里注意CString类的用法
}
同样地,逐步在Lxl工程中添加消息接收函数:
void Cclient::OnReceive(in 31、t nErrorCode)
{
//TODO: Add your specialized code here and/or call the base class
((CLx1Dlg*)(AfxGetApp()一>m_pMainWnd))->ShowMsg();
CSocket::OnReceive(nErrorCode);
}
void CLx1Dig::ShowMsgO
{
char buf[255];
m_client.Receive(buf, 255); //接收消息到 32、buf里面,长度255字节
CString msg;
Msg.Format("%s",buf);
AfxMessageBox(msg); //用AfxMessageBox函数显示接收到的字符串
}
量后的收尾工作不要忘记.即在对话框销毁的时候,关闭Socket连接,释放资源。以下以Lxl工程为例,见图。
void CLxlDlg::OnDestroy()
{
CDialog::OnDestroy();
m_client.Close(); //关闭套接字
}
至此,代码全部添加完毕。






