发送TCP数据包设计题4

更新时间:2023-03-08 07:01:27 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

设计题4:发送TCP数据包

本设计的目的是填充一个TCP数据包,并发送给目的主机。

1)以命令行形式运行:SendTCP source_ip source_port dest_ip dest_port Data 其中SendTCP为程序名,source_ip、source_port、dest_ip和dest_port分别为源IP地址、目的IP地址、源端口和目的端口, Data为数据字段。

2)其他的TCP头部参数请自行设定。

3)数据字段为“This is my homework of network,I am very happy!”。 4)成功发送后在屏幕上输出“send OK”。

引言:

TCP作用

TCP建立连接时的三次握手

在因特网协议族(Internet protocol suite)四层协议中,TCP层是位于IP层之上,应用层之下的传输层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。

应用层向TCP层发送用于网间传输的、用8位字节表示的数据流,然后TCP把数据流分割成适当长度的报文段(通常受该计算机连接的网络的数据链路层的最大传送单元(MTU)的限制)。之后TCP把结果包传给IP层,由它来通过网络将包传送给接收端实体的TCP层。TCP为了保证不发生丢包,就给每个字节一个序号,同时序号也保证了传送到接收端实体的包的按序接收。然后接收端实体对已成功收到的字节发回一个相应的确认(ACK);如果发送端实体在合理的往返时延(RTT)内未收到确认,那么对应的数据(假设丢失了)将会被重传。TCP用一个校验和函数来检验数据是否有错误;在发送和接收时都要计算和校验。

首先,TCP建立连接之后,通信双方都同时可以进行数据的传输,其次,它是全双工的;在保证可靠性上,采用超时重传和捎带确认机制。 在流量控制上,采用滑动窗口协议,协议中规定,对于窗口内未经确认的分组需要重传。 在拥塞控制上,采用广受好评的TCP拥塞控制算法(也称AIMD算法),该算法主要包括三个主要部分:1,加性增、乘性减;2,慢启动;3,对超时事件做出反应。

具体设计:

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首部 {

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 ) {

cksum += *(UCHAR*)buffer; }

cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); }

4.流程图

开始构造原始套接字并初始化填充IP首部计算IP首部校验和构造TCP伪首部填充TCP首部计算TCP首部校验和填充发送缓冲区填入目的地址发送数据包结束

源程序:

SENDTCP:

#include #include #include #include #include #include #include #include

#pragma comment(lib,\) #define IPVER 4

#define MAX_BUFF_LEN 65500 typedef struct ip_hdr { }

IP_HEADER; typedef struct tsd_hdr { }

PSD_HEADER; typedef struct tcp_hdr { }

TCP_HEADER;

USHORT checksum(USHORT *buffer, int size) {

unsigned long cksum=0; while(size >1) {

USHORT th_sport; USHORT th_dport; ULONG th_seq; ULONG th_ack; UCHAR th_lenres; UCHAR th_flag; USHORT th_win; USHORT th_sum; USHORT th_urp; ULONG saddr; ULONG daddr; UCHAR mbz; UCHAR ptcl; USHORT tcpl; UCHAR h_verlen; UCHAR tos; USHORT total_len; USHORT ident; USHORT frag_and_flags; UCHAR ttl; UCHAR proto; USHORT checksum; ULONG sourceIP; ULONG destIP;

cksum+=*buffer++; size -=sizeof(USHORT); } if(size) {

cksum += *(UCHAR*)buffer; }

cksum = (cksum >> 16) + (cksum & 0xffff); cksum += (cksum >>16); return (USHORT)(~cksum); }

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];

const char tcp_send_data[]={\}; BOOL flag; int rect,nTimeOver; if (argc!= 5) {

printf(\); return false; }

if (WSAStartup(MAKEWORD(2,2), &WSAData)!=0) {

printf(\); return false; }

if((sock=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0, WSA_FLAG_OVERLAPPED))==INVALID_SOCKET) {

printf(\); return false; } flag=true;

if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char*)&flag,sizeof(flag))== SOCKET_ERROR) {

printf(\);

return false; }

nTimeOver=1000;

if (setsockopt(sock, SOL_SOCKET, SO_SNDTIMEO, (char*)&nTimeOver, sizeof(nTimeOver))==SOCKET_ERROR) {

printf(\); return false; }

ipHeader.h_verlen=(IPVER<<4 | sizeof(ipHeader)/sizeof(unsigned long)); ipHeader.tos=(UCHAR)0;

ipHeader.total_len=htons((unsigned short)sizeof(ipHeader)+sizeof(tcpHeader)+sizeof(tcp_send_data)); ipHeader.ident=0;

ipHeader.frag_and_flags=0; ipHeader.ttl=128;

ipHeader.proto=IPPROTO_UDP; ipHeader.checksum=0;

ipHeader.sourceIP=inet_addr(argv[1]); ipHeader.destIP=inet_addr(argv[3]); memset(check_Buff,0,MAX_BUFF_LEN);

memcpy(check_Buff,&ipHeader,sizeof(IP_HEADER));

ipHeader.checksum=checksum(check_Buff,sizeof(IP_HEADER)); 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)); tcpHeader.th_dport=htons(atoi(argv[4])); tcpHeader.th_sport=htons(atoi(argv[2])); tcpHeader.th_seq=0; tcpHeader.th_ack=0;

tcpHeader.th_lenres=(sizeof(tcpHeader)/sizeof(unsigned long)<<4|0); tcpHeader.th_flag=2;

tcpHeader.th_win=htons((unsigned short)16384); tcpHeader.th_urp=0; tcpHeader.th_sum=0;

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,&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,sizeof(tcp_send_data)); int datasize=sizeof(IP_HEADER)+sizeof(TCP_HEADER)+sizeof(tcp_send_data); 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(\,WSAGetLastError()); return false; } else

printf(\); closesocket(sock); WSACleanup(); return 1; }

SER:

#include #include #include using namespace std;

#pragma comment(lib, \) int main() {

WSADATA wsaData;

WORD sockVersion = MAKEWORD(2, 2); SOCKET sListen = 0; sockaddr_in sin = {0}; sockaddr_in remoteAddr = {0}; char szText[] = \; int nAddrLen = 0;

nAddrLen = sizeof(sockaddr_in); sin.sin_port = htons(4567);

sin.sin_family = AF_INET;

sin.sin_addr.S_un.S_addr = INADDR_ANY; if (WSAStartup(sockVersion, &wsaData) != 0) { }

sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

if (bind(sListen, (LPSOCKADDR)&sin, sizeof(sin)) == SOCKET_ERROR) { }

if (listen(sListen, 2) == SOCKET_ERROR){ }

SOCKET sClient = INADDR_ANY; while (true) { }

closesocket(sListen); WSACleanup();

sClient = accept(sListen, (SOCKADDR*)&remoteAddr, &nAddrLen); if (sClient == INVALID_SOCKET) { }

send(sClient, szText, strlen(szText), 0); closesocket(sClient);

cout << \ << endl; continue;

cout << \ << endl; return 0;

cout << \ << endl; return 0;

cout << \ << endl; exit(0);

}

TCPCLIENT:

#include #include #include using namespace std;

#pragma comment(lib, \) int main() {

}

WSADATA wsaData;

WORD sockVersion = MAKEWORD(2, 2); SOCKET sock = 0;

if (WSAStartup(sockVersion, &wsaData) != 0) { }

sock = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sock == INVALID_SOCKET) { }

sockaddr_in sin;

sin.sin_family = AF_INET; sin.sin_port = htons(4567);

sin.sin_addr.S_un.S_addr = inet_addr(\); if (connect(sock, (sockaddr*)&sin, sizeof(sockaddr)) == -1) { }

char buffer[256] = \; int nRecv = 0;

nRecv = recv(sock, buffer, 256, 0); if (nRecv > 0) { }

closesocket(sock); WSACleanup();

buffer[nRecv] = '\\0';

cout << \ << buffer << endl; cout << \ << endl; return 0;

cout << \ << endl; return 0;

cout << \ << endl; exit(0);

本文来源:https://www.bwwdw.com/article/fpz.html

Top