计算机网络课程设计报告23795.docx
《计算机网络课程设计报告23795.docx》由会员分享,可在线阅读,更多相关《计算机网络课程设计报告23795.docx(90页珍藏版)》请在冰豆网上搜索。
计算机网络课程设计报告23795
实验报告
实验名称:
计算机网络课程设计
学生姓名:
xxxxxxxxxxxxxxx
专业:
xxxxxxxxxxxxxxx
班级:
xxxxxxxxxxxxxxx
学号:
xxxxxxxxxxxxxxx
指导教师:
xxxxxxxxxxxxxxx
实验成绩:
实验地点:
实验时间:
2016年5
月
6日
一、实验目的与实验要求
1、实验目的
将书本上抽象的概念与具体实现技术结合,通过网络软件编程的实践,深入
理解理论课上学习到的ARP、IP、TCP等重要网络协议的原理,通过自己动手
编程封装与发送这些数据包,加深对网络协议的理解,掌握协议帧的结构和工作
原理及其对协议栈的贡献。
2、实验要求
网络课程设计包含两个部分的内容:
题目一是数据包的封装发送和解析(ARP/IP/TCP),要求使用Winpcap技术
和Socket技术,根据ARP/IP/TCP帧的结构,封装数据包发送到局域网中。
另外要捕获网络中的TCP/IP/ARP数据包,解析数据包的内容,并将结果显示,并同时写入日志文件。
题目二是从可选题目中选择一个,可选题目均是网络应用小程序,要求小组
使用网络编程技术设计并实现一个网络应用程序,加深对网络协议协的理解,并
锻炼网络编程能力。
二、实验设备(环境)及要求
1、实验硬件设备:
计算机型号:
联想ThinkPadT430u
处理器型号:
Inteli5主频:
1.8Hz
网卡型号:
(1)RealtekPCIeGBE
(2)Broadcom802.11n
2、实验软件要求:
操作系统:
Windows10
应用软件:
VisualStudio2015Pro
3、小组成员及分工:
三、实验内容与步骤
1、实验1:
数据包的封装发送和解析(ARP/IP/TCP)
(1)实验内容
1)程序目标:
根据IP帧的结构,封装IP数据包发送到局域网中。
并捕获网络中的IP数据包,
解析数据包的内容,并将结果显示,并同时写入日志文件。
2)程序功能:
以命令行形式运行
在标准输出中显示捕获的IP报文的首部字段的内容。
使用winpcap访问网卡,手动封装
定义IP首部的数据结构
填充数据包,发送数据包,捕获数据包使用winpcap,捕获IP数据包
(2)主要步骤
1)总体设计:
a.获取设备列表并打印,打开所选择的适配器;
b.准备工作:
定义ip相关的结构体、打开要存放结果的文件,设置过滤器,手写ip数据报(内容有无效的MAC源和目的地址,和均为本机地址的ip源地址和目的地址,即发给自己一个ip报文),设置抓到数据报的解析和输出到文件的操作函数(解析ip报,打印并写入文件:
报文的版本、协议、源和目
的地址等)。
c.发包、抓包。
d.分析获取的数据。
获取设备列表
打开选择适配器
过滤数据包
解析数据包
2)具体实现:
#defineHAVE_REMOTE
#include"pcap.h"
#include"remote-ext.h"
#include"stdio.h"
#include"stdlib.h"
/*4字节的IP地址*/
typedefstructip_address{
u_charbyte1;
u_charbyte2;
u_charbyte3;
u_charbyte4;
}ip_address;
/*IPv4首部*/
typedefstructip_header{
u_charver_ihl;
//版本(
4bits)+首部长度(
4bits)
u_chartos;
//服务类型
u_shorttlen;
//总长类型
u_shortidentification;
//标识
u_shortflags_fo;
//标志位
+段偏移量
u_charttl;
//存活时间
u_charproto;
//协议
u_shortcrc;
//首部校验和
ip_addressdaddr;
//目的地址
ip_addresssaddr;
//源地址
u_intop_pad;
//选项与填充
}ip_header;
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);
/*packethandler函数原型*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data);
intmain()
{
pcap_if_t*alldevs;
pcap_if_t*d;
intinum;
inti=0;
pcap_t*adhandle;
charerrbuf[PCAP_ERRBUF_SIZE];
u_intnetmask;
charpacket_filter[]="ip";
//抓包类型
pcap_dumper_t*dumpfile;
/*获取本机设备列表*/
if(pcap_findalldevs_ex(PCAP_SRC_IF_STRING,NULL,&alldevs,errbuf)==-1)
{
fprintf(stderr,"Errorinpcap_findalldevs:
%s\n",errbuf);
exit
(1);
}
/*打印适配器列表*/
for(d=alldevs;d;d=d->next)
{
printf("%d.%s",++i,d->name);
if(d->description)
printf("(%s)\n",d->description);
else
printf("(Nodescriptionavailable)\n");
}
if(i==0)
{
printf("\nNointerfacesfound!
MakesureWinPcapisinstalled.\n");return-1;
}
printf("Entertheinterfacenumber(1-%d):
",i);
scanf("%d",&inum);
if(inum<1||inum>i)
{
printf("\nInterfacenumberoutofrange.\n");
/*释放设备列表*/
pcap_freealldevs(alldevs);
return-1;
}
/*跳转到选中的适配器*/
for(d=alldevs,i=0;inext,i++);
/*打开设备*/
if((adhandle=pcap_open(d->name,//设备名
65536,//65535保证能捕获到不同数据链路层上每个数据包的全部内容
PCAP_OPENFLAG_PROMISCUOUS,
//混杂模式
1000,
//读取超时时间
NULL,
//远程机器验证
errbuf
))==NULL)
//错误缓冲池
{
fprintf(stderr,"\nUnabletoopentheadapter.%sisnotsupportedbyWinPcap\n",
d->name);
/*释放设备列表*/
pcap_freealldevs(alldevs);
return-1;
}
/*打开堆文件*/
dumpfile=pcap_dump_open(adhandle,"D:
\\save.txt");
if(dumpfile==NULL)
{
fprintf(stderr,"\nErroropeningoutputfile\n");
return-1;
}
/*检查数据链路层,只考虑以太网*/
if(pcap_datalink(adhandle)!
=DLT_EN10MB)
{
fprintf(stderr,"nThisprogramworksonlyonEthernetnetwords.n");
/*释放设备列表*/
pcap_freealldevs(alldevs);
return-1;
}
if(d->addresses!
=NULL)
//获得接口第一个地址的掩码
netmask=((structsockaddr_in*)(d->addresses->netmask))->sin_addr.S_un.S_addr;
else
//如果接口没有地址,那么我们假设一个C类的掩码
netmask=0xffffff;
//编译过滤器
if(pcap_compile(adhandle,&fcode,packet_filter,1,netmask)<0)
{
fprintf(stderr,"nUnabletocompilethepacketfilter.Checkthesyntax.n");
//释放设备列表
pcap_freealldevs(alldevs);
return-1;
}
//设置过滤器
if(pcap_setfilter(adhandle,&fcode)<0)
{
fprintf(stderr,"nErrorsettingthefilter.n");
//释放设备列表
pcap_freealldevs(alldevs);
return-1;
}
printf("\nlisteningon%s...\n",d->description);
//释放设备列表
pcap_freealldevs(alldevs);
/*手写数据包*/
u_charpacket[100];
/*假设在以太网上,设置MAC的目的地址为1:
1:
1:
1:
1:
1*/
packet[0]=1;
packet[1]=1;
packet[2]=1;
packet[3]=1;
packet[4]=1;
packet[5]=1;
/*设置MAC的源地址为2:
2:
2:
2:
2:
2*/
packet[6]=2;
packet[7]=2;
packet[8]=2;
packet[9]=2;
packet[10]=2;
packet[11]=2;
/*设置ip类型*/
packet[12]=0x08;
packet[13]=0x00;
packet[14]=0x45;
packet[15]=0x20;
packet[16]=0x00;
packet[17]=0x28;
packet[18]=0xcb;
packet[19]=0x16;
packet[20]=0x00;
packet[21]=0x00;
packet[22]=0x2e;
packet[23]=0x06;
packet[24]=0x3e;
packet[25]=0xe6;
packet[26]=0xc0;//192
packet[27]=0xa8;//168
packet[28]=0x01;//1
packet[29]=0x64;//100
packet[30]=0xc0;
packet[31]=0xa8;
packet[32]=0x01;
packet[33]=0x64;
packet[34]=0x8f;
packet[35]=0x50;
/*填充剩下的内容*/
for(i=36;i<100;i++)
{
packet[i]=i%256;
}
/*发送数据包*/
if(pcap_sendpacket(adhandle,packet,100/*size*/)!
=0)
{
fprintf(stderr,"nErrorsendingthepacket:
n",pcap_geterr(adhandle));
return0;
}else{
printf("Sendsuccessed");
}
/*开始捕获*/
pcap_loop(adhandle,0,packet_handler,(unsignedchar*)dumpfile);//回调方式捕获数据
包
pcap_close(adhandle);
return0;
}
/*每次捕获到数据包时,libpcap都会自动调用这个回调函数*/
voidpacket_handler(u_char*param,conststructpcap_pkthdr*header,constu_char*pkt_data)
{
structtm*ltime;
chartimestr[16];
ip_header*ih;
u_intip_len;
time_tlocal_tv_sec;
//保存数据包到文件中
pcap_dump((u_char*)param,header,pkt_data);
/*将时间戳转换成可识别的格式*/
local_tv_sec=header->ts.tv_sec;
ltime=localtime(&local_tv_sec);
strftime(timestr,sizeoftimestr,"%H:
%M:
%S",ltime);
//打印数据包的时间戳和长度
printf("%s,%.6dlen:
%d\n",timestr,header->ts.tv_usec,header->len);
//获得IP数据包头部的位置
ih=(ip_header*)(pkt_data+14);//以太网头部长度
/*打印IP地址和UDP端口*/
printf("版本+首部长度:
[%u]",ih->ver_ihl);
printf("协议:
[%u]",ih->proto);
printf("
首部校验和
:
[%u]",ih->crc);
printf("目的地
址
:
[%u.%u.%u.%u]",
ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4);
printf("源地址ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4);
:
[%u.%u.%u.%u]\n",
FILE*fp;
fp=fopen("D:
\\jiexi.txt","a+");
fprintf(fp,"解析结果:
");
fprintf(fp,"版本+首部长度:
[%u]",ih->ver_ihl);
fprintf(fp,"协议:
[%u]",ih->proto);
fprintf(fp,"首部校验和:
[%u]",ih->crc);
fprintf(fp,"目的地址:
[%u.%u.%u.%u]",
ih->daddr.byte1,ih->daddr.byte2,ih->daddr.byte3,ih->daddr.byte4);
fprintf(fp,"源地址:
[%u.%u.%u.%u]\n",
ih->saddr.byte1,ih->saddr.byte2,ih->saddr.byte3,ih->saddr.byte4);
fclose(fp);
}
2、实验2:
子网内文件传送
(1)实验内容
(明确的实验内容)
设计并实现一个局域网内部的文件传送工具,使用TCP协议进行可靠文件传输。
以图形界面运行,不同结点上文件自动同步
(2)主要步骤
(详细的实验步骤(系统/方法/算法等),图文结合)
1)问题定义:
实现一个局域网内的文件传送与聊天的软件
2)需求分析:
局域网内的文件传送应当具备以下功能:
在线用户的及时发现和更新
选择一对一或者一对多对话模式
与选择用户进行聊天和文件传输
用户下线通知与更新用户列表
3)系统设计:
参考飞鸽传书的实现原理,总结设计方案如下:
架构设计:
本系统采用本地应用程序设计,仅适用于在同一局域网的主机通信;
互相发现:
本系统运行时启动局域网广播线程,发出包含主机名称、主
机IP以及新加入标识符的广播表明自己新加入;
用户列表:
监听到其他用户的广播信息后更新列表,显示当前在线的用户名和用户IP;
更新列表:
在系统退出时会广播本机信息,标识表明自己离开,其余在线用户接收到信息后更新提示该用户下线;
选择用户:
可以单独选择或者多项选择用户列表中的用户;
发送消息:
选择用户后,在输入框中输入聊天信息,点击“发送”按钮
系统会发送UDP数据包给对应用户的ip地址,端口是8011;
接受消息:
系统实时监听8011端口以接受不同用户发来的消息并展示在
聊天窗口中;
发送文件:
选择指定用户,点击“发送文件”按钮,选择本机相应文件
后,与目标用户建立TCP连接,发送字节流。
端口为8011;
接受文件:
监听到有TCP连接请求时建立实时连接,系统提示用户是否
接收文件,选择接收后选择相应路径与文件名后进行接收,接收成功后
再聊天窗口显示提示信息。
4)详细设计:
①局域网用户列表的建立:
软件启动后定时的使用UDP协议向
255.255.255.255这个广播地址发送广播包,端口设置为8001。
广播包内容包含主机名、IP、标识符等信息,已启动软件的用户通过8001端口收到此广播包后,就会在自己的用户列表中添加这个用户的用户名、IP地址等信息,从而局域网内的本系统用户都能建立起用户列表;
②传送与接收信息:
传送聊天信息时同样使用UDP协议,用户填写消息后点击按钮调用发送消息的函数,然后通过8011端口发送UDP包。
系统在启动时通过开辟新线程来监听8011端口,时刻监听发送到本机的信息。
③发送文件:
用户发送文件时建立一个带参数的线程来发送文件,调用相应的TCP发送函数来发送文件,使用的是8001端口,由于协议不同因此与之前的广播并不冲突;
④接收文件:
软件启动时开启一个线程用来接收文件,此线程在正常工作条件下处于阻塞监听状态,直到收到建立TCP连接的请求,之后提示用户收到文件选择是否接受,之后选择保存路径,进行接收。
⑤用户离开:
用户离线时发送一个离线广播包到255.255.255.255的8001端口,包中含有LEAVE的标识符,收到此广播包的用户,根据包中的IP地址删除用户列表中相应的用户信息,并在聊天窗口显示“XXX用户已经离开”;
⑥聊天记录保存:
考虑到用户有保存聊天记录的需求,在聊天记录右侧点击“保存”按钮,可以将当前聊天记录保存为txt文件到用户指定目录中。
或点
击“清空”,清空当前用户聊天记录。
5)具体实现:
(C#)
usingSystem;
usingSystem.Collections.Generic;
usingSystem.ComponentModel;
usingSystem.Data;
usingSystem.Drawing;
usingSystem.IO;
usingSystem.Linq;
usingSystem.Net;
usingSystem.Net.Sockets;
usingSystem.Text;
usingSystem.Threading;
usingSystem.Threading.Tasks;
usingSystem.Windows.Forms;
namespaceIPMessage
{
publicpartialclassfrmMain:
Form
{
//用户实体
publicclassUser
{
privatestringlocalname;//用户名
publicstringlocalName
{
get{returnlocalname;}
set{localname=value;}
}
privatestringlocalip;//用户IP
publicstringlocalIP
{
get{returnlocalip;}
set{localip=value;}
}
}
//用户数组声明
publicstaticListUserslist=newList();
//获得本机名和本机IP
publicUsergetInfo()
{
Useru=newUser();
stringlocalName=Dns.GetHostName();//获取主机名
//Console.WriteLine("主机名:
{0}",localName);
u.localName=localName;
IPHostEntrylocalHost=Dns.GetHostEntry(localName);
//输出对应的IP地址
IPAddresslocalIP=null;
for(inti=0;i