发送和接收TCP数据包Word文档下载推荐.docx
- 文档编号:4278635
- 上传时间:2023-05-03
- 格式:DOCX
- 页数:15
- 大小:123.44KB
发送和接收TCP数据包Word文档下载推荐.docx
《发送和接收TCP数据包Word文档下载推荐.docx》由会员分享,可在线阅读,更多相关《发送和接收TCP数据包Word文档下载推荐.docx(15页珍藏版)》请在冰点文库上搜索。
或者:
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头。
注意,如果设置IP_HDRINCL选项,那么必须具有administrator权限,要不就必须修改注册表:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\Afd\Parameter\
修改键:
DisableRawSecurity(类型为DWORD),把值修改为1。
如果没有,就添加。
BOOLFlag=TRUE;
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.2构造IP头和TCP头
这里,IP头和TCP头以及TCP伪部的构造请参考下面它们的数据结构。
2.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);
}
3.数据结构与模块说明(功能与流程图)
3.1数据结构
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;
4.源程序
#include<
stdio.h>
winsock2.h>
ws2tcpip.h>
time.h>
windows.h>
string.h>
stdlib.h>
iostream.h>
#pragmacomment(lib,"
ws2_32.lib"
)
#defineIPVER4//IP协议预定
#defineMAX_BUFF_LEN65500//发送缓冲区最大值
typedefstructip_hdr//定义IP首部
UCHARh_verlen;
//4位首部长度,4位IP版本号
//8位服务类型TOS
//16位总长度(字节)
//16位标识
//8位生存时间TTL
//8位协议(TCP,UDP或其他)
//16位IP首部校验和
//32位源IP地址
//32位目的IP地址
typedefstructtsd_hdr//定义TCP伪首部
//源地址
//目的地址
//没用
//协议类型
//TCP长度
typedefstructtcp_hdr//定义TCP首部
//16位源端口
//16位目的端口
//32位序列号
//32位确认号
//4位首部长度/6位保留字
//6位标志位
//16位窗口大小
//16位校验和
//16位紧急数据偏移量
//CheckSum:
计算校验和的子函数
USHORTchecksum(USHORT*buffer,intsize)
unsignedlongcksum=0;
while(size>
{
cksum+=*buffer++;
size-=sizeof(USHORT);
}
if(size)
cksum+=*(UCHAR*)buffer;
cksum=(cksum>
cksum+=(cksum>
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)
WSAStartupError!
\n"
if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,
WSA_FLAG_OVERLAPPED))==INVALID_SOCKET)
SocketSetupError!
flag=true;
if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&
flag,sizeof(flag))==
SOCKET_ERROR)
setsockoptIP_HDRINCLerror!
nTimeOver=1000;
if(setsockopt(sock,SOL_SOCKET,SO_SNDTIMEO,(char*)&
nTimeOver,sizeof(nTimeOver))==SOCKET_ERROR)
setsockoptSO_SNDTIMEOerror!
//填充IP首部
ipHeader.h_verlen=(IPVER<
<
4|sizeof(ipHeader)/sizeof(unsignedlong));
ipHeader.tos=(UCHAR)0;
ipHeader.total_len=htons(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,&
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)
senderror!
:
%d\n"
WSAGetLastError());
else
sendok!
closesocket(sock);
WSACleanup();
return1;
5.运行结果与运行情况
在MicrosoftVisualC++6.0下编写源程序,然后调试成功后运行,生成可执行文件123.exe。
因为该程序是带参数的,所以进入dos,并进入到该可执行文件的目录下后在命令提示行下输入:
sendtcp202.114.181.1202.114.181.2000,运行结果如下:
6.调试报告
6.1调试记录
第一、二天,主要是查阅资料,学习算法。
该期间重点了解了IP首部、TCP首部的结构,以及如何将它们和数据字段一起封装成数据包。
同时也掌握了计算校验和的算法,从而通过该算法分别计算出IP首部和TCP首部的校验和。
接着就是对网络编程接口socket套接字的学习,除了掌握它的初始化外,还对一些经常使用的高级套接字函数进行运用,例如WSAStartup()、WSASocket()、socket()、bind()、listen()、accept()、connect()、sendto()、send()等。
当然根据课程设计的要求,有很多函数并不需要用到。
第三、四天,主要是编程实现,调试源程序,不断发现问题并修改。
调试过程中没有出现重大的语法错误,主要是运行的结果不理想,和预期的结果有差距。
经分析,影响运行结果的主要因素是实现数据包发送的代码部分,相对而言,填充数据包的部分是不容易出错的,因为它是按照规定的格式自定义填充的,只要耐心一点都不会出错。
至于数据包的发送,由于是利用函数sendto()来实现的,最初运行程序时出现了这个错误:
senderror!
10004。
查阅资料得知该错误的信息:
case10004:
error="
Interruptedsystemcall中断的系统呼叫"
break;
。
起初甚至怀疑windowsXP系统下不能正常调用sendto(),并向这个方向尝试了很多修改,问题依然没有得到解决。
最后尝试性的将sendto()中的参数datasize修改位一个很小的具体的值是得到“sendok!
”的运行结果,而只要超过一定值就依然出现以前的问题。
这时我回到源程序中检查发现在自定义IP首部中将协议类型定义TCP(Header.proto=IPPROTO_TCP;
),而sendto()是面向UDP的,将协议类型修改为UDP(Header.proto=IPPROTO_UDP;
后,调试运行成功,问题得到解决。
6.2自我评析和总结
这次的课程设计让我学到了很多东西。
我最大的收获是学会了TCP数据包的填充和发送。
在对TCP数据包进行填充时,首先需要我们去充分了解它的数据结构,在这个过程中可以了解相应字节上应该存放的内容和它们的功能。
在实现TCP数据包的发送中,我第一次深深接触了网络编程接口socket套接字的相关知识,虽然本次的课程设计只用到了其中一小部分知识,但这并不会影响到我对这方面知识的全面了解。
总之这次的课程设计,让我对网络中的数据收发有了一定的了解,并激发了我对计算机网络的浓厚兴趣。
7.参考文献
(1)谢希仁编著,《计算机网络》,电子工业出版社,2003年。
(2)周明天、汪文勇编著,“TCP/IP网络原理与技术”,清华大学出版社,1993年。
(3)上网查询相关资料。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 发送 接收 TCP 数据包