计算机网络课程设计数据包发送和接受程序的实现.docx

上传人:b****4 文档编号:3685179 上传时间:2022-11-24 格式:DOCX 页数:12 大小:111.17KB
下载 相关 举报
计算机网络课程设计数据包发送和接受程序的实现.docx_第1页
第1页 / 共12页
计算机网络课程设计数据包发送和接受程序的实现.docx_第2页
第2页 / 共12页
计算机网络课程设计数据包发送和接受程序的实现.docx_第3页
第3页 / 共12页
计算机网络课程设计数据包发送和接受程序的实现.docx_第4页
第4页 / 共12页
计算机网络课程设计数据包发送和接受程序的实现.docx_第5页
第5页 / 共12页
点击查看更多>>
下载资源
资源描述

计算机网络课程设计数据包发送和接受程序的实现.docx

《计算机网络课程设计数据包发送和接受程序的实现.docx》由会员分享,可在线阅读,更多相关《计算机网络课程设计数据包发送和接受程序的实现.docx(12页珍藏版)》请在冰豆网上搜索。

计算机网络课程设计数据包发送和接受程序的实现.docx

计算机网络课程设计数据包发送和接受程序的实现

《计算机网络》课程设计

 

题目数据包发送和接受程序的实现

学院计算机学院

2012年12月21日

数据包发送和接受程序的实现

一、设计题目与要求

1.设计题目

发送TCP数据包

2.设计要求

本设计的功能是填充一个TCP数据包,并发送给目的主机。

1)以命令行形式运行:

SendTCPsource_ipsource_portdest_ipdest_port,其中SendTCP是程序名,source_ip为源端IP地址,source_port为源端口号,dest_ip为目的地址,dest_port为目的端口号。

2)其他的TCP头部参数请自行设定。

3)数据字段为“Thisismyhomeworkofnetwork,Iamhappy!

”。

4)成功发送后在屏幕上输出“sendOK”。

三、详细设计

本课程设计的目标是发送一个TCP数据包,可以利用原始套接字来完成这个工作。

整个程序由初始化原始套接字和发送TCP数据包两个部分组成。

当应用进程需要通过TCP发送时,它就将此应用层报文传送给执行TCP协议的传输实体。

TCP传输实体将用户数据加上TCP报头,形成TCP数据包,在TCP数据包上增加IP头部,形成IP包。

如图-1显示的是TCP数据包和IP包得关系。

TCP协议的数据传输单位称为报文段,其格式如图-2所示。

报文段报头的长度是20B~60B,选项部分长度最多为40B。

TCP报文段主要包括以下字段。

端口号:

端口号字段包括源端口号和目的端口号。

每个端口号的长度是16位,分别表示发送该TCP包的应用进程的端口号和接收该TCP包的应用进程的端口号。

IP数据

图-1TCP数据包加上IP报头形成IP包

序号:

长度为32位。

由于TCP协议是面向数据流的,它所传送的报文段可以视为连续的数据流,因此需要给每一字节编号。

序号字段的“序号”指的是本报文段数据的第一个字节的序号。

确认号:

该字段的长度为32位,它表示接收端希望接收下一个TCP包的第一个字节的序号。

报文长度:

该字段长度为4位。

TCP报文长度是以4B为一个单元来计算的,实际上报文长度在20B~60B之间。

因此这个字段的值在5~15之间。

选项及填充

图-2TCP数据包头部的格式

保留:

长度为6位,留做今后使用,目前全部置0.

控制:

这个字段定义了6种不同的标志,每一个标志占一位,在同一时间可以设置一位或多位。

URG位为1时,表明应尽快把数据传送给应用程序,否则表明允许数据在缓存中存放一段时间。

RST位为1时,表明要强制切断连接。

SYN位为1时,表明有确立连接的请求,这时,把序号字段的初始值作为序号字段的值,以便开始通信。

FIN位为1时,表明发送放已经没有数据发送了。

窗口大小:

长度为16位,指向必须紧急处理的数据的位置,因此最多能够传送的数据为65535B。

紧急指针:

该字段长度为16,指向必需紧急处理的位置,只有当标志URG=1时紧急指针才生效。

从TCP报头后面的报文数据开始,到紧急指针所指出长度的数据,就是必须紧急处理的数据。

选项:

该字段可以多达40B,包括单字节选项和多字节选项。

校验和:

该字段长度为16位,校验和的校验范围包括伪头部,TCP报头以及应用层来的数据。

其计算方法与IP协议头部校验和的计算方法一样。

伪头部为12B,它本身并不是TCP数据包的真头部,只是在计算校验和时,临时和TCP数据包连接在一起。

伪头部的格式如图-3所示

08162431

源IP地址

目的IP地址

00000000

协议号(6)

TCP长度

1.创建一个原始套接字,并设置IP头选项

SOCKETsock;

sock=socket(AF_INET,SOCK_RAW,IPPROTO_IP);

或者:

sock=WSASoccket(AF_INET,SOCK_RAW,IPPROTO_IP,NULL,0,WSA_FLAG_OVERLAPPED);

这里,设置了SOCK_RAW标志,表示我们声明的是一个原始套接字类型。

为使用发送接收超时设置,必须将标志位置位置为WSA_FLAG_OVERLAPPED。

在本课程设计中,发送TCP包时隐藏了自己的IP地址,因此我们要自己填充IP头,设置IP头操作选项。

其中flag设置为ture,并设定IP_HDRINCL选项,表明自己来构造IP头。

setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&Flag,sizeof(Flag));

inttimeout=1000;

setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,sizeof(timeout));

在这里我们使用基本套接字SOL_SOCKET,设置SO_SNDTIMEO表示使用发送超时设置,超时时间设置为1000ms。

2.构造IP头和TCP头

这里,IP头和TCP头以及TCP伪部的构造请参考下面它们的数据结构。

typedefstruct_iphdr//定义IP首部

{

UCHARh_lenver;//4位首部长度+4位IP版本号

UCHARtos;//8位服务类型TOS

USHORTtotal_len;//16位总长度(字节)

USHORTident;//16位标识

USHORTfrag_and_flags;//3位标志位

UCHARttl;//8位生存时间TTL

UCHARproto;//8位协议(TCP,UDP或其他)

USHORTchecksum;//16位IP首部校验和

ULONGsourceIP;//32位源IP地址

ULONGdestIP;//32位目的IP地址

}IP_HEADER;

typedefstructpsd_hdr//定义TCP伪首部

{

ULONGsaddr;//源地址

ULONGdaddr;//目的地址

UCHARmbz;//没用

UCHARptcl;//协议类型

USHORTtcpl;//TCP长度

}PSD_HEADER;

typedefstruct_tcphdr//定义TCP首部

{

USHORTth_sport;//16位源端口

USHORTth_dport;//16位目的端口

ULONGth_seq;//32位序列号

ULONGth_ack;//32位确认号

UCHARth_lenres;//4位首部长度/6位保留字

UCHARth_flag;//6位标志位

USHORTth_win;//16位窗口大小

USHORTth_sum;//16位校验和

USHORTth_urp;//16位紧急数据偏移量

}TCP_HEADER;

3.计算校验和的子函数

在填充数据包的过程中,需要调用计算校验和的函数checksum两次,分别用于校验IP头和TCP头部(加上伪头部),其实现代码如下:

USHORTchecksum(USHORT*buffer,intsize)

{

unsignedlongcksum=0;

while(size>1)

{

cksum+=*buffer++;

size-=sizeof(USHORT);

}

if(size)

{

cksum+=*(UCHAR*)buffer;

}

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);

return(USHORT)(~cksum);

}

4.流程图

4、调试分析

本程序流程简单,调试过程中没有出现大的问题。

调试过程中没有出现重大的语法错误,主要是运行的结果不理想,和预期的结果有差距。

填充数据包的程序部分是不容易出错的。

至于数据包的发送,由于是利用函数sendto()来实现的,而sendto()是面向UDP的,将协议类型修改为UDP(Header.proto=IPPROTO_UDP;)后,调试运行成功,问题得到解决。

调试时,要添加

#include

#include

#pragmacomment(lib,"ws2_32.lib")

不然编译出错。

5、使用说明

输入:

sendtcp192.168.1.123100192.168.1.124200,然后回车,出现sendok!

表示已经正确发送。

6、源代码

#include

#include

#include

#include

#include

#include

#include

#include

#pragmacomment(lib,"ws2_32.lib")

#defineIPVER4//IP协议预定

#defineMAX_BUFF_LEN65500//发送缓冲区最大值

typedefstructip_hdr//定义IP首部

{

UCHARh_verlen;//4位首部长度,4位IP版本号

UCHARtos;//8位服务类型TOS

USHORTtotal_len;//16位总长度(字节)

USHORTident;//16位标识

USHORTfrag_and_flags;//3位标志位

UCHARttl;//8位生存时间TTL

UCHARproto;//8位协议(TCP,UDP或其他)

USHORTchecksum;//16位IP首部校验和

ULONGsourceIP;//32位源IP地址

ULONGdestIP;//32位目的IP地址

}IP_HEADER;

typedefstructtsd_hdr//定义TCP伪首部

{

ULONGsaddr;//源地址

ULONGdaddr;//目的地址

UCHARmbz;//

UCHARptcl;//协议类型

USHORTtcpl;//TCP长度

}PSD_HEADER;

typedefstructtcp_hdr//定义TCP首部

{

USHORTth_sport;//16位源端口

USHORTth_dport;//16位目的端口

ULONGth_seq;//32位序列号

ULONGth_ack;//32位确认号

UCHARth_lenres;//4位首部长度/6位保留字

UCHARth_flag;//6位标志位

USHORTth_win;//16位窗口大小

USHORTth_sum;//16位校验和

USHORTth_urp;//16位紧急数据偏移量

}TCP_HEADER;

//CheckSum:

计算校验和的子函数

USHORTchecksum(USHORT*buffer,intsize)

{

unsignedlongcksum=0;

while(size>1)

{

cksum+=*buffer++;

size-=sizeof(USHORT);

}

if(size)

{

cksum+=*(UCHAR*)buffer;

}

cksum=(cksum>>16)+(cksum&0xffff);

cksum+=(cksum>>16);

return(USHORT)(~cksum);

}

intmain(intargc,char*argv[])

{

WSADATAWSAData;

SOCKETsock;

IP_HEADERipHeader;

TCP_HEADERtcpHeader;

PSD_HEADERpsdHeader;

charSendto_Buff[MAX_BUFF_LEN];//发送缓冲区

unsignedshortcheck_Buff[MAX_BUFF_LEN];//检验和缓冲区

constchartcp_send_data[]={"Thisismyhomeworkofnetwort,Iamhappy!

"};

BOOLflag;

intrect,nTimeOver;

if(argc!

=5)

{

printf("Useage:

sendtcpsoruce_ipsource_portdest_ipdest_port\n");

returnfalse;

}

if(WSAStartup(MAKEWORD(2,2),&WSAData)!

=0)

{

printf("WSAStartupError!

\n");

returnfalse;

}

if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)

{

printf("SocketSetupError!

\n");

returnfalse;

}

flag=true;

//设置选项值IP_HDRINCL为要设置的选项值

if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag))==SOCKET_ERROR)

{

printf("setsockoptIP_HDRINCLerror!

\n");

returnfalse;

}

nTimeOver=1000;

//设置选项值SO_SNDTIMEO为要设置的选项值

if(setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&nTimeOver,sizeof(nTimeOver))==SOCKET_ERROR)

{

printf("setsockoptSO_SNDTIMEOerror!

\n");

returnfalse;

}

//填充IP首部

ipHeader.h_verlen=(IPVER<<4|sizeof(ipHeader)/sizeof(unsignedlong));

ipHeader.tos=(UCHAR)0;

ipHeader.total_len=htons((unsignedshort)sizeof(ipHeader)+sizeof(tcpHeader)+sizeof(tcp_send_data));

ipHeader.ident=0;//16位标识

ipHeader.frag_and_flags=0;//3位标志位

ipHeader.ttl=128;//8位生存时间

ipHeader.proto=IPPROTO_UDP;//协议类型

ipHeader.checksum=0;//检验和暂时为0

ipHeader.sourceIP=inet_addr(argv[1]);//32位源IP地址

ipHeader.destIP=inet_addr(argv[3]);//32位目的IP地址

//计算IP头部检验和

memset(check_Buff,0,MAX_BUFF_LEN);

memcpy(check_Buff,&ipHeader,sizeof(IP_HEADER));

ipHeader.checksum=checksum(check_Buff,sizeof(IP_HEADER));

//构造TCP伪首部

psdHeader.saddr=ipHeader.sourceIP;

psdHeader.daddr=ipHeader.destIP;

psdHeader.mbz=0;

psdHeader.ptcl=ipHeader.proto;

psdHeader.tcpl=htons(sizeof(TCP_HEADER)+sizeof(tcp_send_data));

//填充TCP首部

tcpHeader.th_dport=htons(atoi(argv[4]));//16位目的端口号

tcpHeader.th_sport=htons(atoi(argv[2]));//16位源端口号

tcpHeader.th_seq=0;//SYN序列号

tcpHeader.th_ack=0;//ACK序列号置为0

//TCP长度和保留位

tcpHeader.th_lenres=(sizeof(tcpHeader)/sizeof(unsignedlong)<<4|0);

tcpHeader.th_flag=2;//修改这里来实现不同的标志位探测,2是SYN,1是//FIN,16是ACK探测等等

tcpHeader.th_win=htons((unsignedshort)16384);//窗口大小

tcpHeader.th_urp=0;//偏移大小

tcpHeader.th_sum=0;//检验和暂时填为0

//计算TCP校验和

memset(check_Buff,0,MAX_BUFF_LEN);

memcpy(check_Buff,&psdHeader,sizeof(psdHeader));

memcpy(check_Buff+sizeof(psdHeader),&tcpHeader,sizeof(tcpHeader));

memcpy(check_Buff+sizeof(PSD_HEADER)+sizeof(TCP_HEADER),tcp_send_data,sizeof(tcp_send_data));

tcpHeader.th_sum=checksum(check_Buff,sizeof(PSD_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data));

//填充发送缓冲区

memset(Sendto_Buff,0,MAX_BUFF_LEN);

memcpy(Sendto_Buff,&ipHeader,sizeof(IP_HEADER));

memcpy(Sendto_Buff+sizeof(IP_HEADER),&tcpHeader,sizeof(TCP_HEADER));

memcpy(Sendto_Buff+sizeof(IP_HEADER)+sizeof(TCP_HEADER),tcp_send_data,sizeof(tcp_send_data));

intdatasize=sizeof(IP_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data);

//发送数据报的目的地址

SOCKADDR_INdest;

memset(&dest,0,sizeof(dest));

dest.sin_family=AF_INET;

dest.sin_addr.s_addr=inet_addr(argv[3]);

dest.sin_port=htons(atoi(argv[4]));

rect=sendto(sock,Sendto_Buff,datasize,0,(structsockaddr*)&dest,sizeof(dest));

if(rect==SOCKET_ERROR)

{

printf("senderror!

:

%d\n",WSAGetLastError());

returnfalse;

}

else

printf("sendok!

\n");

closesocket(sock);

WSACleanup();

return1;

}

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 哲学历史

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1