《TCP和UDP数据包发送与接收要点.pdf》由会员分享,可在线阅读,更多相关《TCP和UDP数据包发送与接收要点.pdf(16页珍藏版)》请在三一文库上搜索。
1、实验 6 TCP和 UDP 数据包发送与接收 一、实验目的 TCP 协议是 TCP/IP 协议族的核心协议之一。 熟悉 TCP 包结构对于理解网络 层次结构,以及 TCP 协议与 IP 协议的关系有着重要意义。 根据 TCP 协议的基本 原理,通过封装与发送一个标准的TCP 数据包,了解 TCP 包结构中各字段的含 义与用途,从而深入理解传输层与下面各层的关系。 二、实验要求 (1)掌握 TCP/UDP 报头结构、各字段含义以及校验和计算方法; (2)使用 Wincap(Lipcap)构造并发送 TCP,UDP 数据包; (3)使用原始套接字 (Raw Socket)发送自定义的 TCP,UD
2、P 数据包; (4)使用 NDIS 协议驱动发送自定义的TCP/UDP 数据包。 三、实验内容 实验一 SOCKET 编程实验 实验内容 1、 通过调试、运行“UDPClient ” 和“ UDPServer”实验程序,加强对网络通讯原理 的了解。(或“简单Client”和“简单Server”实验程序 ,下同) 2、 学习分析实验程序功能结构,了解基于SOCKET编程的网络通信软件的基本设计 方法。 3、 在所提供的” UDPClient ” 和“ UDPServer”实验程序基础上,完善程序功能。 4、 通过实验学习和了解SOKCET 通信的实现方法。 实验结果分析与总结 (1)总结运行”U
3、DPClient ” 和“ UDPServer”实验程序的运行情况。 UDPClient 运行结 UDPServer 运行结果 (2)设计交互程序的运行结果如下: (3)总结程序设计的情况,列出所设计或修改部分的源代码清单。附上程序源代码。 Client 端修改的代码如下: /(3)开始接收或发送过程 printf(“n- waiting for message from Seaver -n“); / 进入一个循环 while (1) / 输入并发送信息给服务器 buffer0=0; /先清空发送缓冲区 printf(“n Input datagram send info ( quit 退出
4、): “); / 输入发送字符串 scanf(“%s“,buffer); sendto(socketid,buffer,sizeof buffer,0,(struct sockaddr*) / 发送信息 / 控制循环退出 if(strcmp(buffer,“quit“) = 0) /输入为 quit则结 束 printf(“n send info quit“); return 0; / 接收服务器返回信息 buffer0=0; / 先清空 接 收缓 冲 区 if(recvfrom(socketid,buffer,sizeof buffer,0,(struct sockaddr*) closes
5、ocket(socketid); /关闭 SOCKET 连 接 WSACleanup(); /退出使用 wsock32.dll动态链接库 return 0; Seaver 端修改的代码如下: printf(“n- waiting for message from client -n“); / 进入一个循环 while (1) buffer0=0; if(recvfrom(socketid,buffer,sizeofbuffer,0,(struct sockaddr*) /给 cilent发信息 / char ack100 = “recv ok!“; / sendto(socketid,ack,
6、sizeof ack,0,(struct sockaddr*) buffer0=0; printf(“n Input datagram send info ( quit 退出 ): “); / 输入发送字符串 scanf(“%s“,buffer); sendto(socketid,buffer,sizeof buffer,0,(struct sockaddr*) /发 if(strcmp(buffer,“quit“) = 0) /输入为 quit则结束 printf(“n send info quit“); return 0; /Sleep(500); closesocket(socketid
7、); WSACleanup(); return 0; 总结: 在 Client 端接收返回信息发送信息和Seaver接收返回信息发送信息前都要进行 清空接收缓冲区。 (1)掌握 TCP/UDP 报头结构、各字段含义以及校验和计算方法; (a)TCP报头结构 TCP 头部数据( data) 各字段含义: 源端口(Source Port )和目的端口 (Destination Port):分别代表本次 TCP 通信 发起主机和目的主机所使用的端口号; 序列号( Sequence Number ):该字段用来标识TCP 源端设备向目的端设备发 送的字节流,它表示在这个报文段中的第几个数据字节。序列号
8、是一个32 位的数。 确认号(Acknowledge Number) :TCP 使用 32 位的确认号字段标识期望收到 的下一个段的第一个字节,并声明此前的所有数据已经正确无误地收到,因 此,确认号应该是上次已成功收到的数据字节序列号加1。收到确认号的源 计算机会知道特定的段已经被收到。确认号的字段只在ACK 标志被设置时 才有效。 数据偏移( Data Offset):这个 4 位字段包括 TCP 头大小。由于首部可能含有 选项内容,因此 TCP 首部的长度是不确定的。首部长度的单位是32 比特或 4 个八位组。首部长度实际上也指示了数据区在报文段中的起始偏移值。 保留( Reserved
9、):6 位置 0 的字段。为将来定义新的用途保留。 、 控制位 (Control Bits):共 6 位,每一位标志可以打开一个控制功能。 URG(Urgent Pointer Field Significant, 紧急指针字段标志 ):表示 TCP 包的 紧急指针字段有效, 用来保证 TCP 连接不被中断, 并且督促中间齐备尽快处 理这些数据。 ACK(Acknowledgement field significant,确认字段标志) : 取 1 时表示应 答字段有效,也即TCP 应答号将包含在 TCP 段中,为 0 则反之。 PSH(Push Function,推功能 ):这个标志表示Pu
10、sh操作。所谓 Push操作 就是指在数据包到达接收端以后,立即送给应用程序,而不是在缓冲区中排 队。 RST (Reset the connection, 重置连接): 这个标志表示感谢连接复位请求, 用来复位那些产生错误的连接,也被用来拒绝错误和非法的数据包。 SYN(Synchronize sequence numbers, 同步序列号) :表示同步序号,用来 建立连接。 FIN(No more data from sender):表示发送端已经发送到数据末尾,数 据传送完成,发送FIN 标志位的 TCP 段,连接将被断开。 窗口(Window):目的主机使用 16 位的窗口字段告诉源主
11、机它期望每次收到 的数据通的字节数。 校验和( Checksum ):TCP 头包括 16 位的校验和字段用于错误检查。源主机 基于部分 IP 头信息, TCP 头和数据内容计算一个校验和,目的主机也要进 行相同的计算,如果收到的内容没有错误过,两个计算应该完全一样,从 而证明数据的有效性。 紧急指针( Urgent Pointer):紧急指针字段是一个可选的16 位指针,指向段 内的最后一个字节位置,这个字段只在URG 标志被设置时才有效。 选项(Option):至少 1 字节的可变长字段,标识哪个选项(如果有的话)有 效。如果没有选项,这个字节等于0,说明选项的结束。这个字节等于1 表示
12、无需再有操作;等于2 表示下四个字节包括源机器的最大长度(Maximum Segment Size,MSS ). 填充( Padding):这个字段中加入额外的零,以保证TCP 头是 32 的整数倍。 (b)UDP 报头结构 源 IP 地址目的 IP 地 址 0 17 UDP 长度 0 15 16 31 32 47 63 伪首部源首部目 的 端 口 长度检验和 UDP 首部数据部分 源端口和目的端口: 16 比特 源端口是可选的,目的端口必须填写。若源端口不选,则取值为0; 长度字段记录 UDP 数据报的总长度,包括UDP 首部和用户数据。长度以八 位组为单位; 校验和字段的内容为整个UDP
13、报文加上伪首部的校验和,计算方法与IP 数 据报首部校验和的算法相同。 校验和计算可选。该字段全0,则表示不计算校验和,用于高效率传输。 UDP 使用全 1来表示校验和值为0。 (c)校验和计算方法; USHORT CheckSum(const char *buf, int size) USHORT *buffer=(USHORT *)buf; unsigned long cksum=0; while(size 1) cksum+=*buffer+; size -=sizeof(USHORT); if(size ) cksum += *(UCHAR*)buffer; cksum = (cksu
14、m 16) + (cksum cksum += (cksum 16); return (USHORT)(cksum); 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 cksum += (cksum 16); return (USHORT)(cksum); unsigned sho
15、rt TcpCheckSum(const char *pTcpData, const char *pPshData, UINT nTcpCount) unsigned short sCheckSum = CheckSum(pTcpData,nTcpCount); unsigned long checkSum = sCheckSum; checkSum next) printf(“%d. %s“, +i, d-name); if (d-description) printf(“ (%s)n“, d-description); else printf(“ (No description avail
16、able)n“); if(i=0) printf(“nNo interfaces found! Make sure WinPcap is installed.n“); return NULL; printf(“Enter the interface number (1-%d):“,i); scanf(“%d“, if(inum i) printf(“nInterface number out of range.n“); /* Free the device list */ pcap_freealldevs(alldevs); return NULL; /* Jump to the select
17、ed adapter */ for(d=alldevs, i=0; inext, i+); /* Open the device */ /* Open the adapter */ if (adhandle= pcap_open_live(d-name, / name of the device 65536, / portion of the packet to capture. / 65536 grants that the whole packet will be captured on all the MACs. 1, / promiscuous mode (nonzero means
18、promiscuous) 1000, / read timeout errbuf / error buffer ) = NULL) fprintf(stderr,“nUnable to open the adapter. %s is not supported by WinPcapn“, d-name); /* Free the device list */ pcap_freealldevs(alldevs); return NULL; pcap_freealldevs(alldevs); return adhandle; int _tmain(int argc, _TCHAR* argv)
19、if(3!=argc) printf(“Wrong Parament!rn“); return 0; /printf (argv1); DWORD dwDestIp= inet_addr(argv1); if(dwDestIp=INADDR_NONE) printf(“Wrong Ip Address!rn“); return 0; if(strlen(argv2)1024) printf(“Too long Parament!rn“); return 0; pcap_t *hWpcapHandle=InitWinpcap(); UCHAR bLocalMac6; DWORD dwDefaul
20、tGateway= 0; DWORD dwLocalIP = 0; DWORD dwNetMask= 0; char strName64; PIP_ADAPTER_INFO pAdapterInfo = NULL; ULONG ulLen = 0; gethostname(strName,64); :GetAdaptersInfo(pAdapterInfo, pAdapterInfo = (PIP_ADAPTER_INFO):GlobalAlloc(GPTR, ulLen); / 取得本地适配器结构信息 if(:GetAdaptersInfo(pAdapterInfo, dwDefaultGa
21、teway= :inet_addr(pAdapterInfo-GatewayList.IpAddress.String); dwLocalIP = :inet_addr(pAdapterInfo-IpAddressList.IpAddress.String); dwNetMask= :inet_addr(pAdapterInfo-IpAddressList.IpMask.String); else return 0; else return 0; char bDestMac8; memset(bDestMac,0xff,6); TcpPacket *pTcpPacket; pTcpPacket
22、=(TcpPacket *)new charsizeof(TcpPacket)+strlen(argv2)+1; strcpy(char*)pTcpPacket)+sizeof(TcpPacket),argv2); ulLen=6; if(SendARP(dwDestIp,0,(PULONG)bDestMac, return 0; memcpy(pTcpPacket-theIpPacket.theEthHead.bDestMac,bDestMac,6); memcpy(pTcpPacket-theIpPacket.theEthHead.bSourceMac,bLocalMac,6); pTcp
23、Packet-theIpPacket.theEthHead.usEthernetType=0x8; pTcpPacket-theIpPacket.theIpHead.ucVersionAndHeadLength=0x45; pTcpPacket-theIpPacket.theIpHead.ucTos=0; pTcpPacket-theIpPacket.theIpHead.usTotalLength=htons(48+strlen(argv2); pTcpPacket-theIpPacket.theIpHead.usIdentification=1234; pTcpPacket-theIpPac
24、ket.theIpHead.usFlagsAndFragmentOffset=0; pTcpPacket-theIpPacket.theIpHead.ucTtl=119; pTcpPacket-theIpPacket.theIpHead.ucProtocol=6;/tcp pTcpPacket-theIpPacket.theIpHead.dwSourceAddr=dwLocalIP; pTcpPacket-theIpPacket.theIpHead.dwDestAddr=dwDestIp; pTcpPacket-theIpPacket.theIpHead.usCrc=0; pTcpPacket
25、-theIpPacket.theIpHead.usCrc=CheckSum(const char *)( pTcpPacket-theTcpHead.usDestPort=htons(1000); pTcpPacket-theTcpHead.usSourcePort=htons(3000); pTcpPacket-theTcpHead.dwSeq=ntohl(198327); pTcpPacket-theTcpHead.dwAck=0; pTcpPacket-theTcpHead.ucLength=0x70; pTcpPacket-theTcpHead.ucFlag=4; pTcpPacket
26、-theTcpHead.usWindow=0xFFFF; /16 位窗口大小 pTcpPacket-theTcpHead.usCrc=0;/16 位校验和 pTcpPacket-theTcpHead.usUrgent=0;/16 位紧急数据偏移量 pTcpPacket-theTcpHead.unMssOpt=htonl(0x020405B4); pTcpPacket-theTcpHead.usNopOpt= 0x0101; pTcpPacket-theTcpHead.usSackOpt= 0x0204; pTcpPacket-theTcpHead.usCrc=0; TcpFakeHeader
27、theTcpFakeHeader; theTcpFakeHeader.bZero=0; theTcpFakeHeader.bTcpLength=htons(28+strlen(argv2); theTcpFakeHeader.bProtocolType=6; theTcpFakeHeader.dwDestAddr=dwDestIp; theTcpFakeHeader.dwSourceAddr=dwLocalIP; pTcpPacket-theTcpHead.usCrc=TcpCheckSum(char *)( if (pcap_sendpacket(hWpcapHandle,(u_char *
28、)pTcpPacket,sizeof(TcpPacket)+strlen(argv2) ) != 0) printf(“nError Sending the TCP Packet: n“, pcap_geterr(hWpcapHandle); else printf(“Send TCP Packet Success!rn“); UdpPacket *pUdpPacket=(UdpPacket *)pTcpPacket; strcpy(char*)pUdpPacket)+sizeof(UdpPacket),argv2); memcpy(pUdpPacket-theEthHead.bDestMac
29、,bDestMac,6); memcpy(pUdpPacket-theEthHead.bSourceMac,bLocalMac,6); pUdpPacket-theEthHead.usEthernetType=0x8; pUdpPacket-theIpHead.ucVersionAndHeadLength=0x45; pUdpPacket-theIpHead.ucTos=0; pUdpPacket-theIpHead.usTotalLength=htons(28+strlen(argv2); pUdpPacket-theIpHead.usIdentification=1234; pUdpPac
30、ket-theIpHead.usFlagsAndFragmentOffset=0; pUdpPacket-theIpHead.ucTtl=119; pUdpPacket-theIpHead.ucProtocol=17;/udp pUdpPacket-theIpHead.dwSourceAddr=dwLocalIP; pUdpPacket-theIpHead.dwDestAddr=dwDestIp; pUdpPacket-theIpHead.usCrc=0; pUdpPacket-theIpHead.usCrc=CheckSum(USHORT*)( pUdpPacket-theUdpHead.u
31、sSourcePort=ntohs(3000); pUdpPacket-theUdpHead.usDestPort=ntohs(2000); pUdpPacket-theUdpHead.usLength=ntohs(8+strlen(argv2); pUdpPacket-theUdpHead.usCrc=0; UdpFakeHeader theUdpFakeHeader; theUdpFakeHeader.bZero=0; theUdpFakeHeader.bUdpLength=htons(sizeof(UdpHead)+strlen(argv2); theUdpFakeHeader.bPro
32、tocolType=17; theUdpFakeHeader.dwSourceAddr=dwLocalIP; theUdpFakeHeader.dwDestAddr=dwDestIp; pUdpPacket-theUdpHead.usCrc=UdpCheckSum(char *) if (pcap_sendpacket(hWpcapHandle,(u_char *)pUdpPacket,sizeof(UdpPacket)+strlen(argv2) ) != 0) printf(“nError sending the packet: n“, pcap_geterr(hWpcapHandle);
33、 return 0; printf(“Send UDP Packet Success!rn“); delete (char*)pTcpPacket; return 0; 程序执行在控制台界面下键入SendPacket “目的地址”“发送内容”,运行 结果如下图: (3)使用原始套接字 (Raw Socket)发送自定义的 TCP,UDP 数据包 ; 1.创建一个原始套接字,并设置IP 头选项 2.构造 UDP 头和 TCP 头 同以上所述。 3.发送原始套接字数据包 发送的时候完全不必考虑目的地址是否与本机在同一个子网中,由于原始套接 字会自动调用下层协议栈相关功能,根据目的IP 地址确定是否应该把数据包发 给网关。 (4)使用 NDIS 协议驱动发送自定义的TCP/UDP 数据包。 【结论】 TCP 和 UDP 协议是工作在传输层得通信协议,其主要目的是实现不同主 机独立进程之间的通信; 其中,TCP 协议提供拥塞控制,可靠传输等功能,UDP 协议比较简单,只是提供不可靠数据传输功能。UDP 数据包的结构是很简单的, 它只包括头部和数据部分,它拥有源端口号,目的端口号,总长度和检验和。相 对而言,TCP 的结构要复杂一点, 但是这两者都是传输层的协议,只是可不可靠 的问题而已。 指导教师评语及成绩 【评语】 【成绩】指导教师签名:日期:年月日
链接地址:https://www.31doc.com/p-5198262.html