TCP数据包的发送和接收设计报告
1 / 11 湖北工业大学
课 程 设 计 报 告
设计题目:TCP数据包的发送和接收
专 业:计算机科学与技术
班 级:10计科2班
学 号:1010311211
姓 名:吕红杰
指导老师:涂军
TCP数据包的发送和接收设计报告
2 / 11 一.设计题目
发送和接收TCP数据包
二.设计要求
1.正确理解题意;
2.具有良好的编程规范和适当的注释;
3.有详细的文档,文档中应包括设计题目涉及的基础知识、设计思路、程序流程图、程序清单、开发中遇到的问题及解决方法、设计中待解决的问题及改进方向。
三.需求分析
TCP是一种面向连接的、可靠的传输层协议。TCP协议工作在网络层IP协议的基础上。本课程设计的目的是设计一个发送和接收TCP数据包的程序,其功能是填充一个TCP数据包,发送给目的主机,并在目的主机接收此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, SOL_SOCKET,SO_SNDTIMEO,(char*)&timeout, sizeof(timeout));
在这里我们使用基本套接字SOL_SOCKET,设置SO_SNDTIMEO表示使用发送超时设置,超时时间设置为1000ms。
2.构造IP头和TCP头
这里, IP头和TCP头以及TCP伪部的构造请参考下面它们的数据结构。
typedef struct _iphdr //定义IP首部
{ TCP数据包的发送和接收设计报告
3 / 11 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 或其他)
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)
{
unsigned long cksum=0;
while(size >1)
{
cksum+=*buffer++;
size -=sizeof(USHORT);
}
if(size )
{ TCP数据包的发送和接收设计报告
4 / 11 cksum += *(UCHAR*)buffer;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
4.流程图
开始构造原始套接字并初始化填充IP首部计算IP首部校验和构造TCP伪首部填充TCP首部计算TCP首部校验和填充发送缓冲区填入目的地址发送数据包结束
五.实验内容
1.先用vc++编译运行程序代码 TCP数据包的发送和接收设计报告
5 / 11 2.用命令指示符运行Debug下的sendTCP
3.输入源ip和端口及目的ip和端口
4.输入发送内容 TCP数据包的发送和接收设计报告
6 / 11
5.发送完成
六.附代码
#include
#include
#include
#include
#include
7 / 11 #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地址
}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;
TCP数据包的发送和接收设计报告
8 / 11 //CheckSum:计算校验和的子函数
USHORT checksum(USHORT *buffer, int size)
{
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);
}
int ReadData(char *str,int maxlen)
{
int readlen=0;
char ch=NULL;
if(str==NULL||maxlen<=0)
{
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--;
}
str[readlen]=NULL;
return readlen;
}
int main(int argc, char* argv[])
{
WSADATA WSAData;
SOCKET sock;