发送TCP数据包.docx
- 文档编号:18107676
- 上传时间:2023-08-13
- 格式:DOCX
- 页数:14
- 大小:103.99KB
发送TCP数据包.docx
《发送TCP数据包.docx》由会员分享,可在线阅读,更多相关《发送TCP数据包.docx(14页珍藏版)》请在冰点文库上搜索。
发送TCP数据包
发送TCP数据包
1.开发环境与工具
VS2012,windows操作系统
2.设计思想与算法结构
本课程设计的目标是发送一个TCP数据包,可以利用原始套接字来完成这个工作。
整个程序由初始化原始套接字和发送TCP数据包两个部分组成。
2.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.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;
2.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);
}
2.4流程图
3.源程序及执行代码说明
#include
#include
#include
#include
#include
#include
#include
#include
#pragmacomment(lib,"ws2_32.lib")
usingnamespacestd;
#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);
}
intReadData(char*str,intmaxlen)
{
intreadlen=0;
charch=NULL;
if(str==NULL||maxlen<=0)
{
printf("ReadDataError!
!
!
\n");
return0;//failed
}
printf("InputData(EndByCtrl+Z):
\n");
while(maxlen)
{
ch=getchar();
if(ch==EOF)break;
str[readlen++]=ch;
maxlen--;
}
str[readlen]=NULL;
returnreadlen;
}
intmain(intargc,char*argv[])
{
WSADATAWSAData;
SOCKETsock;
IP_HEADERipHeader;
TCP_HEADERtcpHeader;
PSD_HEADERpsdHeader;
charSendto_Buff[MAX_BUFF_LEN];//发送缓冲区
unsignedshortcheck_Buff[MAX_BUFF_LEN];//检验和缓冲区
chartcp_send_data[1000];
intread_data_len=0;
BOOLflag;
intrect,nTimeOver;
if(argc!
=5)
{
printf("Usage:
SendTcpsoruce_ipsource_portdest_ipdest_port\n");
returnfalse;
}
read_data_len=ReadData(tcp_send_data,1000);
if(read_data_len<=0)return1;
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;
if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,
(char*)&flag,sizeof(flag))==SOCKET_ERROR)
{
printf("setsockoptIP_HDRINCLerror!
\n");
returnfalse;
}
nTimeOver=1000;
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)+read_data_len);
ipHeader.ident=0;//16位标识
ipHeader.frag_and_flags=0;//3位标志位
ipHeader.ttl=128;//8位生存时间
ipHeader.proto=IPPROTO_TCP;//协议类型
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)+read_data_len);
//填充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,read_data_len);
tcpHeader.th_sum=checksum(check_Buff,sizeof(PSD_HEADER)+
sizeof(TCP_HEADER)+read_data_len);
//填充发送缓冲区
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,read_data_len);
intdatasize=sizeof(IP_HEADER)+sizeof(TCP_HEADER)+read_data_len;
//发送数据报的目的地址
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("\nsendok!
\n");
closesocket(sock);
WSACleanup();
return1;
}
执行代码说明
1.先将程序预编译成字节码文件sendtcp.exe
2.在cmd下执行文件sendtcp.exe
3.输入:
sendtcp127.0.0.180127.0.0.180,
4.输入要发送的字符串:
Thisismyhomeworkofnetwork,Iamhappy!
4.个人体会
调试过程中没有出现重大的语法错误,主要是运行的结果不理想,和预期的结果有差距。
填充数据包的程序部分是不容易出错的。
至于数据包的发送,由于是利用函数sendto()来实现的,而sendto()是面向UDP的,将协议类型修改为UDP(Header.proto=IPPROTO_UDP;)后,调试运行成功,问题得到解决。
调试时,要添加
#include
#include
#pragmacomment(lib,"ws2_32.lib")
不然编译出错。
经过了《计算机网络》的学习,加上这次课设,我对计算机通信有了更深刻的认识。
更加了解了线程的概念,认识了TCP协议在线程通信间起到的重要作用。
了解了套接字(socket)的真正内涵。
计算机这门课程重在实践,只有亲自动手去做,对其中的各种原理才能融会贯通,真正掌握。
5.参考文献
[1]《计算机网络(第5版)》 谢希仁著电子工业出版社2009
[2]《数据通信与网络(第四版)》吴时霖吴永辉译电子工业出版社2010
[3]《C程序设计(第四版)》谭浩强著清华大学出版社2009
[4]《TCP/IP协议族(第三版)》福罗赞著清华大学出版社2010
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 发送 TCP 数据包
![提示](https://static.bingdoc.com/images/bang_tan.gif)