计算机网络 课程设计 发送TCP数据包_tcp数据包发送和接收
计算机网络 课程设计 发送TCP数据包由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“tcp数据包发送和接收”。
课设名称:发送TCP数据包
班级:
学号:
姓名:
指导老师: 日期: 2012.6.15
计算机网络课程设计报告
目录
一.设计题目与要求........................................................................................................2
1.设计题目................................................................................................................2
2.设计要求................................................................................................................2
二.需求分析...................................................................................................................2三.详细设计...................................................................................................................2
1.创建一个原始套接字,并设置IP头选项.................................................................3
2.构造IP头和TCP头...............................................................................................3
3.计算校验和的子函数..............................................................................................4
4.流程图...................................................................................................................6
四.调试分析...................................................................................................................7
五.运行结果...................................................................................................................7
六.总结..........................................................................................................................8
七.源程序......................................................................................................................9
发送TCP数据包
一.设计题目与要求
1.设计题目
发送TCP数据包 2.设计要求
本设计的功能是填充一个TCP数据包,并发送给目的主机。
1)以命令行形式运行:TCP source_ip source_port dest_ip dest_port,其中SendTCP是程序名,source_ip为源端IP地址,source_port为源端口号,dest_ip为目的地址,dest_port为目的端口号。
2)其他的TCP头部参数请自行设定。3)数据字段为“hello”。
4)成功发送后在屏幕上输出“send OK”。
二.需求分析
1.本程序需完成发送一个TCP数据包给目的主机
2.程序的输入:TCP source_ip source_port dest_ip dest_port,然后根据提示输入要发送的数据,回车即可。
3.程序的输出:Send OK!
4.测试数据 TCP 192.168.1.100 200 192.168.1.101 200
三.详细设计
本课程设计的目标是发送一个TCP数据包,可以利用原始套接字来完成这个工作。整个程序由初始化原始套接字和发送TCP数据包两个部分组成。
2发送TCP数据包
1.创建一个原始套接字,并设置IP头选项
SOCKET sock;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));int timeout=1000; setsockopt(sock, sizeof(timeout));在这里我们使用基本套接字SOL_SOCKET,设置SO_SNDTIMEO表示使用发送超时设置,超时时间设置为1000ms。2.构造IP头和TCP头
这里,IP头和TCP头以及TCP伪部的构造请参考下面它们的数据结构。
typedef struct _iphdr //定义IP首部 { UCHAR h_lenver;//4位首部长度+4位IP版本号 UCHAR tos;//8位服务类型TOS
USHORT total_len;//16位总长度(字节)USHORT ident;//16位标识
USHORT frag_and_flags;//3位标志位 UCHAR ttl;//8位生存时间 TTL
UCHAR proto;//8位协议(TCP, UDP 或其他)
SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout,3发送TCP数据包
USHORT checksum;//16位IP首部校验和 ULONG sourceIP;//32位源IP地址
ULONG destIP;//32位目的IP地址
}IP_HEADER;typedef struct psd_hdr //定义TCP伪首部 { ULONG saddr;ULONG daddr;//源地址 //目的地址
UCHAR mbz;//没用 UCHAR ptcl;
USHORT tcpl;//协议类型 //TCP长度
}PSD_HEADER;typedef struct _tcphdr //定义TCP首部 { USHORT th_sport;//16位源端口 USHORT th_dport;//16位目的端口 ULONG th_seq;//32位序列号 ULONG th_ack;//32位确认号
UCHAR th_lenres;//4位首部长度/6位保留字 UCHAR th_flag;//6位标志位 USHORT th_win;//16位窗口大小 USHORT th_sum;//16位校验和 USHORT th_urp;//16位紧急数据偏移量
}TCP_HEADER;
3.计算校验和的子函数
在填充数据包的过程中,需要调用计算校验和的函数checksum两次,分别用于校验IP头和TCP头部(加上伪头部),其实现代码如下:
USHORT checksum(USHORT *buffer, int size)
4发送TCP数据包
{ unsigned long cksum=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);}
5发送TCP数据包
4.流程图
开始构造原始套接字并初始化填充IP首部计算IP首部校验和构造TCP伪首部填充TCP首部计算TCP首部校验和填充发送缓冲区填入目的地址发送数据包结束
6发送TCP数据包
四.调试分析
本程序流程简单,调试过程中没有出现大的问题。
调试过程中没有出现重大的语法错误,主要是运行的结果不理想,和预期的结果有差距。填充数据包的程序部分是不容易出错的。至于数据包的发送,由于是利用函数sendto()来实现的,而sendto()是面向UDP的,将协议类型修改为UDP(Header.proto=IPPROTO_UDP;)后,调试运行成功,问题得到解决。
调试时,要添加 #include #include #pragma comment(lib,“ws2_32.lib”)不然编译出错。
五.运行结果
1.输入:TCP 192.168.1.100 200 192.168.1.101 200
7发送TCP数据包
2.输入要发送的字符串:“hello”按Ctrl+Z发送
六.总结
通过本次课程设计,我对发送TCP数据包的原理有了一定的了解。理解了TCP数据报的报文格式、TCP连接时的三次握手和TCP连接结束时的四次握手的过程及它们的作用。此外,在设计过程中,通过查阅资料,也让我对TCP的三大特点(流量控制、差错控制、拥塞控制)有了认识。,在课程设计过程中,由于编程知识的欠缺,使我在课程设计过程中不是很顺利,编程知识的欠缺是我的最大障碍,不过,这也给了我动力,我会努力去学好编程的相关知识,为以后的学习和工作打下基础。最后,感谢老师安排了此次课程设计。
发送TCP数据包
七.源程序
#include #include #include #include #include #include #include #include #pragma comment(lib,“ws2_32.lib”)
#define IPVER 4 //IP协议预定 #define MAX_BUFF_LEN 65500 //发送缓冲区最大值
typedef struct ip_hdr //定义IP首部 {
UCHAR h_verlen;//4位首部长度,4位IP版本号 UCHAR tos;//8位服务类型TOS USHORT total_len;//16位总长度(字节)USHORT ident;//16位标识 USHORT frag_and_flags;//3位标志位 UCHAR ttl;//8位生存时间 TTL UCHAR proto;//8位协议(TCP, UDP 或其他)USHORT checksum;//16位IP首部校验和 ULONG sourceIP;//32位源IP地址 ULONG destIP;//32位目的IP地址
发送TCP数据包
}IP_HEADER;
typedef struct tsd_hdr //定义TCP伪首部 {
ULONG saddr;//源地址 ULONG daddr;//目的地址 UCHAR mbz;//没用 UCHAR ptcl;//协议类型 USHORT tcpl;//TCP长度
}PSD_HEADER;
typedef struct tcp_hdr //定义TCP首部 {
USHORT th_sport;//16位源端口 USHORT th_dport;//16位目的端口 ULONG th_seq;//32位序列号 ULONG th_ack;//32位确认号
UCHAR th_lenres;//4位首部长度/6位保留字 UCHAR th_flag;//6位标志位 USHORT th_win;//16位窗口大小 USHORT th_sum;//16位校验和
USHORT th_urp;//16位紧急数据偏移量
}TCP_HEADER;
//CheckSum:计算校验和的子函数
USHORT checksum(USHORT *buffer, int size){ unsigned long cksum=0;while(size >1)
发送TCP数据包
{ cksum+=*buffer++;size-=sizeof(USHORT);} if(size){ cksum += *(UCHAR*)buffer;} cksum =(cksum >> 16)+(cksum & 0xffff);cksum +=(cksum >>16);return(USHORT)(~cksum);}
int ReadData(char *str,int maxlen){ int readlen=0;char ch=NULL;if(str==NULL||maxlen
printf(“ReadData Error!!n”);
return 0;//failed } printf(“Input Data(End By Ctrl+Z): n”);while(maxlen){
ch=getchar();
if(ch==EOF)break;
str[readlen++]=ch;maxlen--;
发送TCP数据包
} } str[readlen]=NULL;return readlen;int main(int argc, char* argv[]){ WSADATA WSAData;SOCKET sock;
IP_HEADER ipHeader;TCP_HEADER tcpHeader;PSD_HEADER psdHeader;
char Sendto_Buff[MAX_BUFF_LEN];//发送缓冲区
unsigned short check_Buff[MAX_BUFF_LEN];//检验和缓冲区 char tcp_send_data[1000];
BOOL flag;int rect,nTimeOver;if(argc!= 5){ printf(“Usage: SendTcp soruce_ip source_port dest_ip dest_port n”);return false;} read_data_len=ReadData(tcp_send_data,1000);int read_data_len=0;
发送TCP数据包
if(read_data_len
if(WSAStartup(MAKEWORD(2,2), &WSAData)!=0){ printf(“WSAStartup Error!n”);return false;} if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0, WSA_FLAG_OVERLAPPED))==INVALID_SOCKET){ printf(“Socket Setup Error!n”);return false;} flag=true;if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag))==SOCKET_ERROR){ printf(“setsockopt IP_HDRINCL error!n”);return false;} nTimeOver=1000;if(setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO,(char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR){ printf(“setsockopt SO_SNDTIMEO error!n”);return false;}
发送TCP数据包
//填充IP首部
ipHeader.h_verlen=(IPVER
//计算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位源端口号
发送TCP数据包
tcpHeader.th_seq=0;//SYN序列号 tcpHeader.th_ack=0;//ACK序列号置为0 //TCP长度和保留位
tcpHeader.th_lenres=(sizeof(tcpHeader)/sizeof(unsigned long)
tcpHeader.th_win=htons((unsigned short)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));
//填充发送缓冲区
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(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);memcpy(Sendto_Buff+sizeof(IP_HEADER)+sizeof(TCP_HEADER), tcp_send_data,read_data_len);
发送TCP数据包
int datasize=sizeof(IP_HEADER)+sizeof(TCP_HEADER)+read_data_len;//发送数据报的目的地址 SOCKADDR_IN dest;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,(struct sockaddr*)&dest, sizeof(dest));if(rect==SOCKET_ERROR){ printf(“send error!:%dn”,WSAGetLastError());return false;} else
closesocket(sock);WSACleanup();return 1;} printf(“nsend ok!n”);