当前位置:文档之家› TCP协议实验

TCP协议实验

网络课第四次上机实验报告------TCP协议实验实验内容实验内容主要包括:设计保存TCP 连接相关信息的数据结构(TCB);TCP 协议的接收处理和封装发送;TCP 协议提供的Socket 函数接口。

实验过程设计保存TCP 连接相关信息的数据结构(TCB)用数据结构TCB为每一个TCP连接维护socketfd,srcAddr,dstAddr, srcPort, dstPort, seq, ack, wind owSize, state这些状态信息。

以链表形式组织多个连接,nextTcb指向下一个连接的数据结构。

TCP 分组接收函数stud_tcp_input( )首先,检查校验和;然后通过字节序转换获取相应的信息,检查序列号。

如果序列号不正确,则调用tcp_DiscardPkt;最后将报文交由输入有限状态机处理,有限状态机对报文进行处理,转换状态。

根据当前的状态并调用stud_tcp_output 函数完成tcp 建连、数据传递时返回ACK、tcp 断连等工作TCP 分组发送函数stud_tcp_output ( )判断需要发送的报文类型,根据报的类型对包中的相应字段进行设置,判断是否可以发送(发送窗口不为0)。

构造TCP 数据报文并发送。

填写TCP 报文各字段的内容和数据,转换字节序,计算校验和,然后调用发送流程的下层接口函数sendIpPkt( )发送。

stud_tcp_socket ( )函数分配相应的socketfd并且新建TCB表项,并对成员变量进行初始化stud_tcp_connect ( )函数设定目的IPv4 地址和端口,源IPv4 地址和端口;初始化TCB 结构中的相关变量;设定TCB 中的输入状态为SYN-SENT,及其它相关变量,准备发送SYN 报文;调用发送流程的下层接口函数stud_tcp_output ( )发送SYN 报文(发送类型为PACKET_TYPE_SYN);等待“三次握手”完成后返回,建立连接成功;或者出错返回。

stud_tcp_send ( )函数判断是否处于ESTABLISHED 状态;将应用层协议的数据拷贝到TCB 的输入缓冲区;调用stud_tcp_output ( )发送TCP 的数据报文(发送类型为PACKET_TYPE_DATA);同时等待ACK以实现停等式协议stud_tcp_recv ( )函数判断是否处于ESTABLISHED 状态;从TCB 的输入缓冲区读出数据;将数据交给应用层协议。

stud_tcp_close ( )函数在正常情况下(ESTABLISHED 状态),进行相应状态转换,非正常情况下(SYN-SENT 状态),直接删除TCB 结构后退出;调用发送流程下层接口函数stud_tcp_output ( )发送FIN 报文(发送类型为PACKET_TYPE_FIN);等待回应的ACK 报文,收到后成功返回,或者出错返回;删除相应的TCB表项。

实验总结通过本次实验,加深了对TCP 协议的原理和设计实现的机制的了解,对TCP协议有了更具体的认识,对概论课的学习有很大的帮助!附:上机代码(注释)#include "sysInclude.h"extern void tcp_DiscardPkt(char *pBuffer, int type);extern void tcp_sendReport(int type);extern void tcp_sendIpPkt(unsigned char *pData, UINT16 l en, unsigned int srcAddr, unsigned int dstAddr, UINT8 ttl);extern int waitIpPacket(char *pBuffer, int timeout);extern unsigned int getIpv4Address();extern unsigned int getServerIpv4Address();#define BUFFER_SIZE 1024#define TIMEOUT 5enum status{CLOSED,SYN_SENT,ESTABLISHED,FIN_WAIT_1,FIN_WAIT_2,TIME_WAIT}; //状态int gSrcPort = 2007;int gDstPort = 2006;int gSeqNum = 1;int gAckNum = 0;struct TCB {int socketfd;UINT32 srcAddr;UINT32 dstAddr;UINT16 srcPort;UINT16 dstPort;UINT32 seq;UINT32 ack;UINT16 wind owSize;UINT8 state;TCB *nextTcb;TCB() { // 用于TCP报文接收发送流程socketfd = 0;srcAddr = getIpv4Address();dstAddr = getServerIpv4Address();srcPort = gSrcPort;dstPort = gDstPort;seq = gSeqNum;ack = gAckNum;windowSize = 1;state = CLOSED;nextTcb = NULL;}TCB(int fd) { // 用于客户端socket函数的构建函数socketfd = fd;seq = gSeqNum;ack = gAckNum;windowSize = 1;state = CLOSED;nextTcb = NULL;}};UINT16 Cal cChecksum(char *pBuffer, int l en, UINT32 srcAddr, UINT32 dstAddr) {int tcp_l en = l en + 12;UINT32 checkSum = 0;if(tcp_l en & 0x1 == 1)tcp_l en += 1;char *buffer = new char[tcp_l en];memset(buffer, 0, tcp_l en);memcpy(buffer + 12, pBuffer, l en);*((UINT32 *)buffer) = htonl(srcAddr);*((UINT32 *)(buffer + 4)) = htonl(dstAddr);buffer[9] = 6; // 传输层协议号*((UINT16 *)(buffer + 10)) = htons(l en);for (int i = 0; i < tcp_l en; i += 2) {checkSum += *((UINT16 *)(buffer + i));}checkSum = (checkSum & 0xFFFF) + (checkSum >> 16);checkSum = ~checkSum;return checkSum;}TCB *tcbLinkTabl e = NULL; // TCB链表/* 通过两端的IP地址和端口号寻找TCB表项*/TCB* findTCB(UINT32 srcAddr, UINT16 srcPort, UINT32 dstAddr, UINT16 dstPort){TCB* tcb = tcbLinkTabl e;whil e(tcb != NULL){if((tcb->srcAddr == srcAddr) && (tcb->srcPort == srcPort) && (tcb->dstAddr == dstAddr) && (tcb->dstPort == dstPort))return tcb;tcb = tcb->nextTcb;}return NULL;}int stud_tcp_input(char *pBuffer, unsigned short l en, unsigned int srcAddr, unsigned int dstAddr){/* 检查校验和*/if (Cal cChecksum(pBuffer, l en, ntohl(srcAddr), ntohl(dstAddr)) != 0)return -1;UINT16 srcPort = ntohs(*(UINT16 *)pBuffer);UINT16 dstPort = ntohs(*(UINT16 *)(pBuffer + 2));UINT32 seq = ntohl(*((UINT32 *)(pBuffer + 4)));UINT32 ack = ntohl(*((UINT32 *)(pBuffer + 8)));UINT8 flags = (pBuffer[13] & 0x13);TCB *tcb = findTCB(ntohl(dstAddr), dstPort, ntohl(srcAddr), srcPort);if(tcb == NULL){return -1;}if(ack != tcb->seq + 1){tcp_DiscardPkt(pBuffer, STUD_TCP_TEST_SEQNO_ERROR);return -1;}/* 有限状态机转换*/if((tcb->state == SYN_SENT) && (flags == 0x12)){tcb->seq = ack;tcb->ack = seq + 1;stud_tcp_output(NULL, 0, PACKET_TYPE_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);tcb->state = ESTABLISHED;}else if((tcb->state == FIN_WAIT_1) && (flags == 0x10)){tcb->state = FIN_WAIT_2;}else if((tcb->state == FIN_WAIT_2) && (flags == 0x11)){tcb->ack = seq + 1;tcb->seq = ack;tcb->state = TIME_WAIT;stud_tcp_output(NULL, 0, PACKET_TYPE_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);tcb->state = CLOSED;}return 0;}void stud_tcp_output(char *pData, unsigned short l en, unsigned char flag, unsigned short srcPort, unsigned short dstPort, unsigned int srcAddr, unsigned int dstAddr){TCB *tcb = findTCB(srcAddr, srcPort, dstAddr, dstPort); // 寻找TCB项if(tcbLinkTabl e == NULL) // 用于TCP报文接收发送流程{tcb = new TCB();tcbLinkTabl e = tcb;}if(tcb == NULL || tcb->wind owSize == 0)return;/* 构造新的发送报文*/unsigned char *packet = new unsigned char[l en + 20];memset(packet, 0, l en + 20);memcpy(packet + 20, pData, l en);*(UINT16 *)(packet) = htons(tcb->srcPort);*(UINT16 *)(packet + 2) = htons(tcb->dstPort);*(UINT32 *)(packet + 4) = htonl(tcb->seq);*((UINT32 *)(packet + 8)) = htonl(tcb->ack);packet[12]=20<<2;switch(flag){case PACKET_TYPE_SYN:packet[13]=0x02;tcb->state = SYN_SENT; // 发送SYN报文,状态转移为SYN_SENTbreak;case PACKET_TYPE_ACK:packet[13]=0x10;break;case PACKET_TYPE_SYN_ACK:packet[13]=0x12;break;case PACKET_TYPE_FIN:packet[13]=0x01;break;case PACKET_TYPE_FIN_ACK:packet[13]=0x11;tcb->state = FIN_WAIT_1;break;case PACKET_TYPE_DATA:break;}*((UINT16 *)(packet+14))=htons(tcb->windowSize);*((UINT16 *)(packet+16))=Cal cChecksum((char *)packet, l en + 20, srcAddr, dstAddr);tcp_sendIpPkt(packet, l en + 20, tcb->srcAddr, tcb->dstAddr, 255);return;}int stud_tcp_socket(int domain, int type, int protocol){static int socketfd = 1;TCB *tcb = new TCB(socketfd++);tcb->nextTcb = tcbLinkTabl e;tcbLinkTabl e = tcb;return tcb->socketfd;}int stud_tcp_connect(int sockfd, struct sockaddr_in *addr, int addrl en){char buffer[BUFFER_SIZE];TCB* tcbPointer = tcbLinkTabl e;whil e((tcbPointer != NULL) && (tcbPointer->socketfd != sockfd))tcbPointer = tcbPointer->nextTcb;TCB *tcb = tcbPointer; // 找到TCB相应表项if(tcb == NULL)return -1;/* 初始化源和目的的地址及端口号*/tcb->srcAddr = getIpv4Ad dress();tcb->srcPort = gSrcPort;tcb->dstAddr = ntohl(addr->sin_addr.s_addr);tcb->dstPort = ntohs(addr->sin_port);/* 建立连接:发送SYN报文*/stud_tcp_output(NULL, 0, PACKET_TYPE_SYN, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);/* 接收SYN_ACK报文*/if(waitIpPacket(buffer, TIMEOUT) == -1 || (buffer[13] & 0x13) != 0x12)return -1;tcb->seq = ntohl(*((UINT32 *)(buffer + 8)));tcb->ack = ntohl(*((UINT32 *)(buffer + 4))) + 1;/* 发送ACK报文,建立连接完成*/stud_tcp_output(NULL, 0, PACKET_TYPE_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);tcb->state = ESTABLISHED;return 0;}int stud_tcp_send(int sockfd, const unsigned char *pData, unsigned short datal en, int flags){char buffer[BUFFER_SIZE];TCB* tcbPointer = tcbLinkTabl e;whil e((tcbPointer != NULL) && (tcbPointer->socketfd != sockfd))tcbPointer = tcbPointer->nextTcb;TCB *tcb = tcbPointer; // 找到TCB相应表项if(tcb == NULL || tcb->state != ESTABLISHED)return -1;/* 发送DATA报文*/stud_tcp_output((char *)pData, datal en, PACKET_TYPE_DATA, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);/* 等待接收ACK */if(waitIpPacket(buffer, TIMEOUT) == -1)return -1;if((buffer[13] & 0x13) != 0x10)return -1;tcb->seq = ntohl(*((UINT32 *)(buffer + 8)));tcb->ack = ntohl(*((UINT32 *)(buffer + 4))) + 1;return 0;}int stud_tcp_recv(int sockfd, unsigned char *pData, unsigned short datal en, int flags){char buffer[BUFFER_SIZE];int l en = 0;TCB* tcbPointer = tcbLinkTabl e;whil e((tcbPointer != NULL) && (tcbPointer->socketfd != sockfd))tcbPointer = tcbPointer->nextTcb;TCB *tcb = tcbPointer;if(tcb == NULL || tcb->state != ESTABLISHED)return -1;/* 等待接收数据*/if((l en = waitIpPacket(buffer, TIMEOUT)) == -1)return -1;int header_l ength = (buffer[12] >> 2) & 0x3C;memcpy(pData, buffer + header_l ength, l en - header_l ength);tcb->seq = ntohl(*((UINT32 *)(buffer + 8)));tcb->ack = ntohl(*((UINT32 *)(buffer + 4))) + (l en - header_l ength);stud_tcp_output(NULL, 0, PACKET_TYPE_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);return 0;}int stud_tcp_cl ose(int sockfd){char buffer[BUFFER_SIZE];TCB *pre = NULL;TCB *tcb = tcbLinkTabl e;whil e((tcb != NULL) && (tcb->socketfd != sockfd)){pre = tcb;tcb = tcb->nextTcb;}if(tcb == NULL)return -1;if(tcb->state != ESTABLISHED){if(pre != NULL){pre->nextTcb = tcb->nextTcb;}else{tcbLinkTabl e = tcb->nextTcb;}del ete tcb;return -1;}stud_tcp_output(NULL, 0, PACKET_TYPE_FIN_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);if(waitIpPacket(buffer, TIMEOUT) == -1)return -1;if((buffer[13] & 0x13) == 0x10){tcb->state = FIN_WAIT_2;tcb->seq = ntohl(*((UINT32 *)(buffer + 8)));tcb->ack = ntohl(*((UINT32 *)(buffer + 4))) + 1;if(waitIpPacket(buffer, TIMEOUT) == -1)return -1;if((buffer[13] & 0x13) == 0x11){tcb->state = TIME_WAIT;tcb->ack = ntohl(*((UINT32 *)(buffer + 4))) + 1;tcb->seq = ntohl(*((UINT32 *)(buffer + 8)));stud_tcp_output(NULL, 0, PACKET_TYPE_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);}else{return -1;}}else{return -1;}if(pre != NULL)pre->nextTcb = tcb->nextTcb;elsetcbLinkTabl e = tcb->nextTcb;del ete tcb;return 0;}。

相关主题