湖北工业大学课程设计报告设计题目:TCP数据包的发送和接收专业:计算机科学与技术班级:10计科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_OVERLAPPE D);这里,设置了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 算校验和的子函数在填充数据包的过程中,需要调用计算校验和的函数checksum两次,分别用于校验IP头和TCP头部(加上伪头部),其实现代码如下: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);}4.流程图五.实验内容1.先用vc++编译运行程序代码2.用命令指示符运行Debug下的sendTCP3.输入源ip和端口及目的ip和端口4.输入发送内容5.发送完成六.附代码#include <>#include <>#include <>#include <>#include <>#include <>#include <>#include <>#pragma comment(lib,"")#define IPVER 4 //IP协议预定#define MAX_BUFF_LEN 65500 //发送缓冲区最大值typedef struct ip_hdr //定义IP首部{UCHAR h_verlen; //4位首部长度,4位IP版本号UCHAR tos; //8位服务类型TOSUSHORT total_len; //16位总长度(字节)USHORT ident; //16位标识USHORT frag_and_flags; //3位标志位UCHAR ttl; //8位生存时间 TTLUCHAR 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;//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;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];int read_data_len=0;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);if(read_data_len<=0) return 1;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;}//填充IP首部=(IPVER<<4 | sizeof(ipHeader)/sizeof(unsigned long));=(UCHAR)0;=htons((unsignedshort)sizeof(ipHeader)+sizeof(tcpHeader)+read_data_len);=0; //16位标识=0; //3位标志位=128; //8位生存时间=IPPROTO_TCP; //协议类型=0; //检验和暂时为0=inet_addr(argv[1]); //32位源IP地址=inet_addr(argv[3]); //32位目的IP地址//计算IP头部检验和memset(check_Buff,0,MAX_BUFF_LEN);memcpy(check_Buff,&ipHeader,sizeof(IP_HEADER));=checksum(check_Buff,sizeof(IP_HEADER));//构造TCP伪首部=;=;=0;=;=htons(sizeof(TCP_HEADER)+read_data_len);//填充TCP首部=htons(atoi(argv[4])); //16位目的端口号=htons(atoi(argv[2])); //16位源端口号=0; //SYN序列号=0; //ACK序列号置为0//TCP长度和保留位=(sizeof(tcpHeader)/sizeof(unsigned long)<<4|0);=2; //修改这里来实现不同的标志位探测,2是SYN,1是//FIN,16是ACK探测等等=htons((unsigned short)16384); //窗口大小=0; //偏移大小=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);=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_IN dest;memset(&dest,0,sizeof(dest));=AF_INET;=htons(atoi(argv[4]));rect=sendto(sock,Sendto_Buff,datasize, 0,(struct sockaddr*)&dest, sizeof(dest));if (rect==SOCKET_ERROR){printf("send error!:%d\n",WSAGetLastError());return false;}elseprintf("\nsend ok!\n");closesocket(sock);WSACleanup();return 1;}。