编号:_______________本资料为word版本,可以直接编辑和打印,感谢您的下载TCP协议实验甲方:___________________乙方:___________________日期:___________________网络课第四次上机实验报告—__TCP协议实验率实验内容实验内容主要包括:设计保存TCP连接相关信息的数据结构(TCB;TCP协议的接收处理和封装发送;TCP协议提供的Socket函数接口。
4实验过程设计保存TCP连接相关信息的数据结构(TC0 mt DINT32 ?工皿1如; UINT32 dstfiddr: 口INTL6 arcForu- ni!4T16 datPort;UIIU3Z UINT32 ack; UIMT1« windowSize; Uli-ITS state; ICB ^nextlGib;用数据结构TCB为每一个TCP连接维护socketfd , srcAddr , dstAddr, srcPort, dstPort, seq, ack, windowSize, 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表项, 并对成员变量进行初始化设定目的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 的输入缓冲区读出数据;将数据交给应用层协议。
在正常情况下(ESTABLISHED犬态),进行相应状态转换,非正常情况下(SYN-SENT状态),直接删除TCB结构后退出;调用发送流程下层接口函数stud_tcp_output ()发送FIN报文(发送类型为PACKET_TYPE_FJN 等待回应的ACK报文,收到后成功返回,或者出错返回;删除相应的TCB表项。
4实验总结通过本次实验,加深了对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 len, unsigned intsrcAddr, 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 windowSize;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 CalcChecksum(char *pBuffer, int len, UINT32 srcAddr, UINT32 dstAddr) {int tcp_len = len + 12;UINT32 checkSum = 0;if(tcp_len & 0x1 == 1)tcp_len += 1;char *buffer = new char[tcp_len];memset(buffer, 0, tcp_len);memcpy(buffer + 12, pBuffer, len);*((UINT32 *)buffer) = htonl(srcAddr);*((UINT32 *)(buffer + 4)) = htonl(dstAddr);buffer[9] = 6; // 传输层协议号*((UINT16 *)(buffer + 10)) = htons(len);for (int i = 0; i < tcp_len; i += 2) {checkSum += *((UINT16 *)(buffer + i));}checkSum = (checkSum & 0xFFFF) + (checkSum >> 16);checkSum = ~checkSum;return checkSum;}TCB *tcbLinkTable = NULL; // TCB 链表/* 通过两端的IP地址和端口号寻找TCB表项*/TCB* findTCB(UINT32 srcAddr, UINT16 srcPort, UINT32 dstAddr, UINT16 dstPort){TCB* tcb = tcbLinkTable;while(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 len, unsigned int srcAddr,unsigned int dstAddr){/*检查校验和*/if (CalcChecksum(pBuffer, len, 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;*pData, unsigned short len, unsigned char flag,void stud_tcp_output(charunsigned short srcPort, unsigned short dstPort, unsigned int srcAddr, unsignedint dstAddr){TCB *tcb = findTCB(srcAddr, srcPort, dstAddr, dstPort); // 寻找TCB 项if(tcbLinkTable == NULL) // 用于TCP报文接收发送流程{tcb = new TCB();tcbLinkTable = tcb;}if(tcb == NULL || tcb->windowSize == 0)return;/*构造新的发送报文*/unsigned char *packet = new unsigned char[len + 20];memset(packet, 0, len + 20);memcpy(packet + 20, pData, len);*(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_SENT break;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))=CalcChecksum((char *)packet, len + 20, srcAddr, dstAddr);tcp_sendIpPkt(packet, len + 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 = tcbLinkTable;tcbLinkTable = tcb;return tcb->socketfd;)int stud_tcp_connect(int sockfd, struct sockaddr_in *addr, int addrlen){char buffer[BUFFER_SIZE];TCB* tcbPointer = tcbLinkTable;while((tcbPointer != NULL) && (tcbPointer->socketfd != sockfd))tcbPointer = tcbPointer->nextTcb;TCB *tcb = tcbPointer; // 找至V TCB 木目应表项if(tcb == NULL)return -1;/*初始化源和目的的地址及端口号*/tcb->srcAddr = getIpv4Address();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 datalen, int flags) (char buffer[BUFFER_SIZE];TCB* tcbPointer = tcbLinkTable;while((tcbPointer != NULL) && (tcbPointer->socketfd != sockfd))tcbPointer = tcbPointer->nextTcb;TCB *tcb = tcbPointer; // 找至V TCB 木目应表项if(tcb == NULL || tcb->state != ESTABLISHED) return -1;/* 发送DATA报文*/stud_tcp_output((char *)pData, datalen, 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 datalen,int flags)(char buffer[BUFFER_SIZE];int len = 0;TCB* tcbPointer = tcbLinkTable;while((tcbPointer != NULL) && (tcbPointer->socketfd != sockfd))tcbPointer = tcbPointer->nextTcb;TCB *tcb = tcbPointer;if(tcb == NULL || tcb->state != ESTABLISHED) return -1;/*等待接收数据*/if((len = waitIpPacket(buffer, TIMEOUT)) == -1)return -1;int header_length = (buffer[12] >> 2) & 0x3C;memcpy(pData, buffer + header_length, len - header_length);tcb->seq = ntohl(*((UINT32 *)(buffer + 8)));tcb->ack = ntohl(*((UINT32 *)(buffer + 4))) + (len - header_length);stud_tcp_output(NULL, 0, PACKET_TYPE_ACK, tcb->srcPort, tcb->dstPort, tcb->srcAddr, tcb->dstAddr);return 0;) int stud_tcp_close(int sockfd)(char buffer[BUFFER_SIZE];TCB *pre = NULL;TCB *tcb = tcbLinkTable;while((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(tcbLinkTable = tcb->nextTcb;)delete 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; elsetcbLinkTable = tcb->nextTcb;delete tcb;return 0;。