UDP文件传输
数据传输协议

数据传输协议数据传输协议是计算机网络中用于实现数据传输和通信的一种规范或约定。
它定义了数据传输的格式、顺序和错误检测等方面的细节,以确保网络中的数据能够准确、高效地传输和接收。
本文将探讨数据传输协议的概念、分类以及常见的应用。
一、概述数据传输协议是计算机网络中用于实现数据传输和通信的一种规范或约定。
它规定了数据传输的各个环节中数据的封装、分组、传输、接收和处理等过程,确保数据在网络中能够准确无误地传递。
二、分类根据不同的要求和应用场景,数据传输协议可以分为以下几种常见的类型:1. 传输控制协议(TCP)TCP是一种面向连接的、可靠的传输协议。
它通过建立一个虚拟的连接来实现数据的可靠传输和流控制。
TCP使用滑动窗口机制进行数据分段,同时具备流量控制和拥塞控制等功能,确保数据能够按序、可靠地传输。
2. 用户数据报协议(UDP)UDP是一种面向无连接的、不可靠的传输协议。
它不需要建立连接,只是简单地将数据包发送出去,不提供任何传输保证。
UDP适用于实时性要求较高但可靠性要求较低的应用场景,比如视频流、音频等。
3. 网络文件系统协议(NFS)NFS是一种分布式文件系统协议,用于共享和访问远程文件系统。
它基于TCP协议,支持在不同的操作系统上共享文件和目录,实现文件的远程传输和访问。
4. 文件传输协议(FTP)FTP是一种用于在网络间进行文件传输的协议。
它可通过TCP协议在客户端和服务器之间进行文件的上传和下载操作。
5. 超文本传输协议(HTTP)HTTP是一种用于在客户端和服务器之间传输超文本的协议。
它基于TCP/IP协议栈,是支持万维网运行的基础。
三、应用数据传输协议在计算机网络中具有广泛的应用,其中一些常见的应用包括:1. 互联网通信:TCP/IP协议是互联网传输层和网络层的核心协议,负责实现互联网上各个主机之间的通信和数据传输。
2. 文件传输和共享:FTP和NFS等协议实现了文件在不同主机之间的传输和共享,方便用户在网络中进行文件的上传和下载操作。
基于UDP的文件传输实验报告

基于UDP的文件传输实验报告实验报告成绩2015年6月8 日实验名称:基于UDP的文件传输1.实验目的(1)熟练掌握Socket编程;(2)分析UDP与TCP的异同。
2.实验设备和条件硬件环境:PC机操作系统:Windows 或者Linux语言环境:Visual C++ ,VS,GCC,Java均可3.实验要求参考TCP文件传输demo, 基于UDP实现send.mp3文件的传输,并测试接收到的文件与发送的文件是否一致。
请各位同学于第15周星期三或星期四上课时将纸质版(双面打印)上交!4.实验内容:测试数据与实验结果(可以抓图粘贴)(1)发送端代码。
#include"stdafx.h"#include<Winsock2.h>#include<stdio.h>#define MAX_LENGTH 1024int_tmain(int argc, _TCHAR* argv[]){WORD wVersionRequested;WSADATA wsaData;wVersionRequested = MAKEWORD(2, 2);if (WSAStartup(wVersionRequested, &wsaData) != 0)//初始化ws2_32.dll动态库{printf("WSAStartup() failed!\n");//Winsock初始化错误exit(-1);}if (wsaData.wVersion != wVersionRequested){printf("The version of Winsock is not suited!\n");//Winsock版本不匹配WSACleanup();//结束对ws2_32.dll的调用exit(-2);}//说明ws2_32.dll正确加载printf("Load ws2_32.dll successfully!\n");//创建套接字SOCKET servsock;printf("Create Socket...\n");servsock = socket(AF_INET, SOCK_DGRAM, 0);//数据报套接字int servport = 5555;int iSockErr = 0;//定义服务器地址结构sockaddr_in udpaddr;int len = sizeof(udpaddr);memset(&udpaddr, 0, sizeof(udpaddr));udpaddr.sin_family = AF_INET;udpaddr.sin_port = htons(servport);//将一个点分十进制IP地址字符串转换成32位数字表示的IP地址udpaddr.sin_addr.s_addr = inet_addr("172.16.4.94");////INADDR_ANY//读取mp3文件FILE *fp = NULL;errno_t err;err = fopen_s(&fp, "七里香.mp3", "rb");if (fp == NULL){printf("Open File Failed!\n");getchar();exit(-5);}char buffer[MAX_LENGTH] = "\0";char *bufptr = buffer;int i = 0;while (!feof(fp)){int iBytesRead = fread(bufptr, 1, MAX_LENGTH, fp);int iRet = sendto(servsock, buffer, sizeof(buffer), 0, (struct sockaddr*)&udpaddr, len);if (iRet != SOCKET_ERROR){iRet = recvfrom(servsock, buffer, sizeof(buffer), 0, (struct sockaddr*)&udpaddr, &len);}else{printf("send file failed!\n");break;}if (iRet == SOCKET_ERROR){//closesocket(clisock);printf("send file failed!\n");break;}else if (iRet == 0){printf("send mp3 file successfully!\n");break;}if (iBytesRead == 0){printf("send mp3 file successfully!\n");break;}//printf("%d", &len);printf("send packet %d lenth: %d\n", i++, iBytesRead);Sleep(10);}sendto(servsock, "", 0, 0, (struct sockaddr*)&udpaddr, len);//关闭shutdown(servsock, 2);closesocket(servsock);WSACleanup();getchar();return 0;}(2)接收端代码。
UDP协议详解

UDP协议详解UDP(User Datagram Protocol)是一种无连接的传输层协议,它提供了一种简单的、不可靠的数据传输服务。
与TCP协议相比,UDP协议不提供数据完整性、可靠性和流量控制等特性,但由于其简单性和低开销,UDP协议在一些特定的应用场景中被广泛使用。
本文将详细解释UDP协议的工作原理、特点和使用场景。
一、UDP协议的工作原理UDP协议使用简单的数据报文形式进行通信。
数据报文是由一个UDP首部和应用层数据组成的,UDP首部包含了源端口号、目的端口号、长度和校验和等字段。
UDP协议不需要建立连接,数据报文可以直接发送给目的主机。
UDP协议的工作流程如下:1. 发送端将应用层数据传递给UDP协议。
2. UDP协议在数据报文中添加首部信息。
3. UDP协议将数据报文发送给目的主机。
4. 接收端的UDP协议从数据报文中提取应用层数据并传递给应用程序。
二、UDP协议的特点1. 无连接:UDP协议不需要建立连接,发送端和接收端之间的通信是无状态的。
2. 不可靠:UDP协议不提供数据的可靠传输,数据报文可能会丢失、重复或乱序。
3. 简单高效:UDP协议的首部开销小,处理速度快。
4. 支持一对一、一对多和多对多的通信模式。
5. 不提供拥塞控制和流量控制等功能。
三、UDP协议的使用场景1. 实时应用:UDP协议适用于实时应用,如音频、视频和实时游戏。
由于UDP协议的低延迟和简单性,可以实现实时数据的快速传输。
2. DNS服务:域名系统(DNS)使用UDP协议进行域名解析。
由于DNS查询通常是短小的请求和响应,使用UDP协议可以减少开销。
3. 广播和多播:UDP协议支持广播和多播,可以将数据报文发送给多个主机,适用于组播视频、在线会议等应用。
4. SNMP协议:简单网络管理协议(SNMP)使用UDP协议进行网络设备的管理和监控。
5. TFTP协议:简单文件传输协议(TFTP)使用UDP协议进行文件的传输。
netcat udp用法

netcat udp用法
Netcat是一个网络工具,可以用于创建TCP或UDP连接,进行
端口扫描,数据传输等。
对于UDP连接,可以使用netcat来进行简
单的UDP数据包发送和接收。
要使用netcat进行UDP连接,可以按照以下步骤操作:
1. 发送UDP数据包:
使用以下命令格式发送UDP数据包:
`nc -u [目标主机] [目标端口]`。
例如,要向主机192.168.1.100的端口5000发送UDP数据包,可以使用以下命令:
`nc -u 192.168.1.100 5000`。
然后输入要发送的数据,按下Enter键即可发送UDP数据包。
2. 接收UDP数据包:
使用以下命令格式接收UDP数据包:
`nc -ul [本地端口]`。
例如,要在本地监听端口5000并接收UDP数据包,可以使用以下命令:
`nc -ul 5000`。
当有UDP数据包到达时,它们将被显示在终端上。
需要注意的是,由于UDP是无连接的协议,因此在使用netcat 进行UDP通信时,不会建立持久的连接,而是单纯地发送和接收数据包。
另外,使用netcat进行UDP通信时,需要确保目标主机和端口是可达的,防火墙不会阻挡UDP数据包的传输。
总之,使用netcat进行UDP连接可以通过简单的命令实现UDP 数据包的发送和接收,方便快捷地进行基本的UDP通信。
基于UDP的文件传输

报告编号:11 综合课程设计报告基于UDP协议的文件传输系统的设计与实现学生姓名:指导教师:所在系:电子系所学专业:电子信息工程年级:08级电子(2)班2011 年6 月目录摘要 (3)1 实验的相关知识 (4)1.1通信的模式 (4)1.2 UDP协议 (4)1.3 Winsock控件 (4)1.3.1 Winsock控件重要属性、方法和事件 (5)1.3.2 Winsock控件通信的工作原理 (7)2 实验原理 (7)3 实验步骤 (7)3.1总体规划 (8)3.2模块设计 (8)3.3创建窗体 (8)3.4程序设计 (10)3.5系统运行 (11)4实验结论 (12)参考文献 (13)基于UDP的文件传输的系统的设计与实现摘要该实验的任务是实现文件的传输,并且是基于UDP协议的。
所有文件在该协议下可以实现发送并正确接收。
此时需要了解的是UDP的数据包一次最多只能发送8K,所以我们想到通过拆包和创建窗体的方法来实现文件的传输。
拆包主要是规定每个数据包的大小,然后计算具体的文件所需要的包数,创建窗体的目的是编写程序来进行分包发送和接收。
通过系统运行窗体我们可以知道UDP不仅可以传送和接收小文件,还可以传输和接收较大的文件。
通过实验可知UDP是不可靠的无连接传输,所以在传输过程中会发生丢包的情况,但大部分情况下传输还是比较好的。
关键词:UDP协议发送文件接收文件拆包 Winsock控件1 实验的相关知识1.1通信的模式由于是实现点对点的文件传输,因此在程序中我们使用的是C/S的模式来实现通信。
对于C/S的模式,即分为客户端和服务端。
服务端用来接收客户端的连接,实现两端之间互相传输文件。
采用C/S的模式可以更好的体现程序的功能设计思想,充分调用在LAN中的server和client两方面的处理能力,极大的减少网络上的信息流通量。
C/S体系结构有可能提供一种开放式的、易伸缩扩展的分布式计算机环境,并保护硬件等投资。
udp协议发送端和接收端的实现步骤

udp协议发送端和接收端的实现步骤一、UDP协议概述UDP(User Datagram Protocol)是一种无连接的传输层协议,它提供了一种不可靠的、面向数据包的数据传输服务。
与TCP协议不同,UDP不保证数据包的顺序和可靠性,但传输效率高,适用于一些对实时性要求较高的应用场景。
二、UDP发送端实现步骤1. 创建UDP套接字:使用socket()函数创建一个UDP套接字,指定协议族为IPv4或IPv6。
2. 绑定端口:使用bind()函数将套接字与本地IP地址和端口号绑定,以便接收方能够正确地将数据包发送到该端口。
3. 构建数据包:将待发送的数据封装成数据包,包括目标IP地址、目标端口号和数据内容。
4. 发送数据包:使用sendto()函数将数据包发送到指定的目标IP 地址和端口号。
5. 关闭套接字:使用close()函数关闭套接字。
三、UDP接收端实现步骤1. 创建UDP套接字:使用socket()函数创建一个UDP套接字,指定协议族为IPv4或IPv6。
2. 绑定端口:使用bind()函数将套接字与本地IP地址和端口号绑定,以便接收数据包。
3. 接收数据包:使用recvfrom()函数从绑定的端口接收数据包,函数返回接收到的数据包内容以及发送方的IP地址和端口号。
4. 处理数据包:根据具体应用需求对接收到的数据包进行处理,例如提取数据内容并进行相应的业务逻辑处理。
5. 关闭套接字:使用close()函数关闭套接字。
四、UDP发送端和接收端的交互过程1. 发送方创建UDP套接字,并绑定本地IP地址和端口号。
2. 接收方创建UDP套接字,并绑定本地IP地址和端口号。
3. 发送方将数据封装成数据包,并通过sendto()函数发送给接收方的IP地址和端口号。
4. 接收方使用recvfrom()函数接收到数据包,并提取数据内容进行处理。
5. 接收方可以选择回复数据给发送方,将数据封装成数据包,并通过sendto()函数发送给发送方的IP地址和端口号。
TCP与UDP的区别及其应用

TCP与UDP的区别及其应用TCP(传输控制协议)和UDP(用户数据报协议)是两种不同的传输协议,它们在网络通信中起着非常重要的作用。
虽然它们都是在网络通信中传输数据的协议,但是它们有很大的区别。
在本文中,我将分别介绍TCP和UDP的特点、区别及其在各种应用中的使用。
一、TCP的特点及应用1. TCP的特点TCP是一种面向连接的协议,它在传输数据之前需要先建立连接,然后传输数据,传输结束后再断开连接。
它提供可靠的、按序传输的数据传输服务,能够保证数据的完整性和可靠性。
TCP使用三次握手来建立连接,四次挥手来断开连接,在传输数据时会进行数据校验和确认。
因此,它非常适合对数据传输的要求比较高的应用场景。
2. TCP的应用TCP广泛应用于各种需要可靠传输的应用场景,包括但不限于以下几个方面:(1)网络浏览:当用户访问网页时,浏览器会使用TCP协议与服务器建立连接,传输页面内容。
(2)文件传输:在文件传输过程中,TCP可以保证文件的完整性和可靠性,确保文件在传输过程中不会丢失或损坏。
(3)电子邮件:电子邮件的发送和接收过程中需要使用TCP协议来保证数据传输的可靠性。
(4)远程登录:如Telnet、SSH等远程登录方式都使用TCP协议来传输数据。
(5)数据库访问:数据库访问时需要使用TCP协议来传输数据。
二、UDP的特点及应用1. UDP的特点UDP是一种无连接的协议,它不需要在传输数据之前建立连接,也不保证数据的完整性和可靠性。
UDP是一种简单的数据传输协议,它仅提供数据传输的功能,不对数据传输进行确认和校验。
因此,UDP的传输效率比TCP高,但可靠性较差。
由于UDP不需要建立连接,所以它的开销比较小,适合对实时性要求较高的应用场景。
2. UDP的应用UDP主要用于那些对实时性要求较高的应用场景,包括但不限于以下几个方面:(1)实时视频、音频传输:视频会议、实时语音通话等应用中使用UDP来传输数据,因为在这些应用中,实时性比可靠性更为重要。
UDP实现可靠文件传输

UDP实现可靠文件传输大家都清楚,如果用TCP传输文件的话,是很简单的,根本都不用操心会丢包,除非是网络坏了,就得重来。
用UDP的话,因为UDP是不可靠的,所以用它传输文件,要保证不丢包,就得我们自己写额外的代码来保障了。
本文就说说如何保证可靠传输。
要实现无差错的传输数据,我们可以采用重发请求(ARQ)协议,它又可分为连续ARQ 协议、选择重发ARQ协议、滑动窗口协议。
本文重点介绍滑动窗口协议,其它的两种有兴趣的可参考相关的网络通信之类的书。
采用滑动窗口协议,限制已发送出去但未被确认的数据帧的数目。
循环重复使用已收到的那些数据帧的序号。
具体实现是在发送端和接收端分别设定发送窗口和接收窗口。
(1)发送窗口发送窗口用来对发送端进行流量控制。
发送窗口的大小Wt代表在还没有收到对方确认的条件下,发送端最多可以发送的数据帧的个数。
具体意思请参考下图:(2)接收窗口接收窗口用来控制接收数据帧。
只有当接收到的数据帧的发送序号落在接收窗口内,才允许将该数据帧收下,否则一律丢弃。
接收窗口的大小用Wr来表示,在连续ARQ协议中,Wr = 1。
接收窗口的意义可参考下图:在接收窗口和发送窗口间存在着这样的关系:接收窗口发生旋转后,发送窗口才可能向前旋转,接收窗口保持不动时,发送窗口是不会旋转的。
这种收发窗口按如此规律顺时钟方向不断旋转的协议就犯法为滑动窗口协议。
好了,在上面对滑动窗口协议有大致了解后,我们还是进入正题吧:)发送端的发送线程:int ret;int nPacketCount = 0;DWORD dwRet;SendBuf sendbuf;DWORD dwRead;DWORD dwReadSize;SendBuf* pushbuf;//计算一共要读的文件次数,若文件已读完,但客户端没有接收完,//则要发送的内容不再从文件里读取,而从m_bufqueue里提取nPacketCount = m_dwFileSize / sizeof(sendbuf.buf);//若不能整除,则应加1if(m_dwFileSize % sizeof(sendbuf.buf) != 0)++nPacketCount;SetEvent(m_hEvent);CHtime htime;//若已发送大小小于文件大小并且发送窗口前沿等于后沿,则继续发送//否则退出循环if(m_dwSend < m_dwFileSize) // 文件没有传输完时才继续传输{while(1){dwRet = WaitForSingleObject(m_hEvent, 1000);if(dwRet == WAIT_FAILED){return false;}else if(dwRet == WAIT_TIMEOUT){//重发::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue的排斥区ret = m_hsocket.hsendto((char*)m_bufqueue.front(), sizeof(sendbuf));::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue的排斥区if(ret == SOCKET_ERROR){cout << "重发失败,继续重发" << endl;continue;}ResetEvent(m_hEvent);continue;}//若发送窗口大小< 预定大小&& 已读文件次数(nReadIndex) < 需要读文件的次数(nReadCount),则继续读取发送//否则,要发送的内容从m_bufqueue里提取if(m_dwSend < m_dwFileSize){dwReadSize = m_dwFileSize - m_dwSend;dwReadSize = dwReadSize < MAXBUF_SIZE ? dwReadSize : MAXBUF_SIZE;memset(sendbuf.buf, 0, sizeof(sendbuf.buf));if(!ReadFile(m_hFile, sendbuf.buf, dwReadSize, &dwRead, NULL)){//AfxMessageBox("读取文件失败,请确认文件存在或有读取权限.");cout << "读取文件失败,请确认文件存在或有读取权限." << endl;return false;}m_dwSend += dwRead;sendbuf.index = m_nSendIndexHead;m_nSendIndexHead = (m_nSendIndexHead + 1) % Sliding_Window_Size; // 发送窗口前沿向前移一格sendbuf.dwLen = dwRead;//保存发送过的数据,以便重发::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue的排斥区pushbuf = GetBufFromLookaside();memcpy(pushbuf, &sendbuf, sizeof(sendbuf));m_bufqueue.push(pushbuf);if(m_dwSend >= m_dwFileSize) // 文件已读完,在队列中加一File_End标志,以便判断是否需要继续发送{pushbuf = GetBufFromLookaside();pushbuf->index = File_End;pushbuf->dwLen = File_End;memset(pushbuf->buf, 0, sizeof(pushbuf->buf));m_bufqueue.push(pushbuf);}::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue的排斥区}::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue的排斥区if(m_bufqueue.front()->index == File_End) // 所有数据包已发送完毕,退出循环{::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue的排斥区break;}else if(m_bufqueue.size() <= Send_Window_Size) // 发送窗口小于指定值,继续发送{ret = m_hsocket.hsendto((char*)m_bufqueue.front(), sizeof(sendbuf));if(ret == SOCKET_ERROR){::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue的排斥区cout << "发送失败,重发" << endl;continue;}//延时,防止丢包Sleep(50);}else // 发送窗口大于指定值,等持接收线程接收确认消息{ResetEvent(m_hEvent);}::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue的排斥区}}发送端的接收线程:int ret;RecvBuf recvbuf;while(m_hFile != NULL){ret = m_hsocket.hrecvfrom((char*)&recvbuf, sizeof(recvbuf));if(ret == SOCKET_ERROR){//AfxMessageBox("接收确认消息出错");::EnterCriticalSection(&m_csQueue);if(m_bufqueue.front()->index == File_End) // 文件传输完毕{::LeaveCriticalSection(&m_csQueue);break;}::LeaveCriticalSection(&m_csQueue);cout << "接收确认消息出错: " << GetLastError() << endl;return false;}if(recvbuf.flag == Flag_Ack && recvbuf.index == m_nSendIndexTail) {m_nSendIndexTail = (m_nSendIndexTail + 1) % Sliding_Window_Size;//该结点已得到确认,将其加入旁视列表,以备再用::EnterCriticalSection(&m_csQueue);m_bufLookaside.push(m_bufqueue.front());m_bufqueue.pop();::LeaveCriticalSection(&m_csQueue);SetEvent(m_hEvent);}}接收端的接收线程:int ret;DWORD dwWritten;SendBuf recvbuf;RecvBuf sendbuf;int nerror = 0;// 设置文件指针位置,指向上次已发送的大小SetFilePointer(m_hFile, 0, NULL, FILE_END);//若已接收文件大小小于需要接收的大小,则继续while(m_dwSend < m_dwFileSize){//接收memset(&recvbuf, 0, sizeof(recvbuf));ret = m_hsocket.hrecvfrom((char*)&recvbuf, sizeof(recvbuf));if(ret == SOCKET_ERROR){return false;}//不是希望接收的,丢弃,继续接收if(recvbuf.index != (m_nRecvIndex) % Sliding_Window_Size){nerror++;cout << recvbuf.index << "error?" << m_nRecvIndex << endl; continue;}if(!WriteFile(m_hFile, recvbuf.buf, recvbuf.dwLen, &dwWritten, NULL)) {//AfxMessageBox("写入文件失败");cout << "写入文件失败" << endl;return false;}//已接收文件大小m_dwSend += dwWritten;//发送确认消息sendbuf.flag = Flag_Ack;sendbuf.index = m_nRecvIndex;ret = m_hsocket.hsendto((char*)&sendbuf, sizeof(sendbuf));if(ret == SOCKET_ERROR){return false;}//接收窗口前移一格m_nRecvIndex = (m_nRecvIndex + 1) % Sliding_Window_Size;}。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
1.实验目的了解udp文件传输过程,掌握传输方法。
2.实验内容要实现无差错的传输数据,我们可以采用重发请求(ARQ)协议,它又可分为连续ARQ 协议、选择重发ARQ 协议、滑动窗口协议。
本文重点介绍滑动窗口协议,其它的两种有兴趣的可参考相关的网络通信之类的书。
采用滑动窗口协议,限制已发送出去但未被确认的数据帧的数目。
循环重复使用已收到的那些数据帧的序号。
具体实现是在发送端和接收端分别设定发送窗口和接收窗口。
3.实验总结学会了udp协议传输和代码设计,了解了udp的格式。
发送端的发送线程:int ret;int nPacketCount = 0;DWORD dwRet;SendBuf sendbuf;DWORD dwRead;DWORD dwReadSize;SendBuf* pushbuf;//计算一共要读的文件次数,若文件已读完,但客户端没有接收完,//则要发送的内容不再从文件里读取,而从m_bufqueue 里提取nPacketCount = m_dwFileSize / sizeof(sendbuf.buf);//若不能整除,则应加1if(m_dwFileSize % sizeof(sendbuf.buf) != 0)++nPacketCount;SetEvent(m_hEvent);CHtime htime;//若已发送大小小于文件大小并且发送窗口前沿等于后沿,则继续发送//否则退出循环if(m_dwSend < m_dwFileSize) // 文件没有传输完时才继续传输{while(1){dwRet = WaitForSingleObject(m_hEvent, 1000);if(dwRet == WAIT_FAILED){return false;}else if(dwRet == WAIT_TIMEOUT){//重发::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue 的排斥区ret = m_hsocket.hsendto((char*)m_bufqueue.front(), sizeof(sendbuf));::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区if(ret == SOCKET_ERROR){cout << "重发失败,继续重发" << endl;continue;}ResetEvent(m_hEvent);continue;}//若发送窗口大小< 预定大小&& 已读文件次数(nReadIndex) < 需要读文件的次数(nReadCoun t),则继续读取发送//否则,要发送的内容从m_bufqueue 里提取if(m_dwSend < m_dwFileSize){dwReadSize = m_dwFileSize - m_dwSend;dwReadSize = dwReadSize < MAXBUF_SIZE ? dwReadSize : MAXBUF_SIZE;memset(sendbuf.buf, 0, sizeof(sendbuf.buf));if(!ReadFile(m_hFile, sendbuf.buf, dwReadSize, &dwRead, NULL)){//AfxMessageBox("读取文件失败,请确认文件存在或有读取权限.");cout << "读取文件失败,请确认文件存在或有读取权限." << endl;return false;}m_dwSend += dwRead;sendbuf.index = m_nSendIndexHead;m_nSendIndexHead = (m_nSendIndexHead + 1) % Sliding_Window_Size; // 发送窗口前沿向前移一格sendbuf.dwLen = dwRead;//保存发送过的数据,以便重发::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue 的排斥区pushbuf = GetBufFromLookaside();memcpy(pushbuf, &sendbuf, sizeof(sendbuf));m_bufqueue.push(pushbuf);if(m_dwSend >= m_dwFileSize) // 文件已读完,在队列中加一File_End 标志,以便判断是否需要继续发送{pushbuf = GetBufFromLookaside();pushbuf->index = File_End;pushbuf->dwLen = File_End;memset(pushbuf->buf, 0, sizeof(pushbuf->buf));m_bufqueue.push(pushbuf);}::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区}::EnterCriticalSection(&m_csQueue); // 进入m_bufqueue 的排斥区if(m_bufqueue.front()->index == File_End) // 所有数据包已发送完毕,退出循环{::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区break;}else if(m_bufqueue.size() <= Send_Window_Size) // 发送窗口小于指定值,继续发送{ret = m_hsocket.hsendto((char*)m_bufqueue.front(), sizeof(sendbuf));if(ret == SOCKET_ERROR){::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区cout << "发送失败,重发" << endl;continue;}//延时,防止丢包}else // 发送窗口大于指定值,等持接收线程接收确认消息{ResetEvent(m_hEvent);}::LeaveCriticalSection(&m_csQueue); // 退出m_bufqueue 的排斥区}}发送端的接收线程:int ret;RecvBuf recvbuf;while(m_hFile != NULL){ret = m_hsocket.hrecvfrom((char*)&recvbuf, sizeof(recvbuf));if(ret == SOCKET_ERROR){//AfxMessageBox("接收确认消息出错");::EnterCriticalSection(&m_csQueue);if(m_bufqueue.front()->index == File_End) // 文件传输完毕{::LeaveCriticalSection(&m_csQueue);break;}::LeaveCriticalSection(&m_csQueue);cout << "接收确认消息出错: " << GetLastError() << endl;return false;}if(recvbuf.flag == Flag_Ack && recvbuf.index == m_nSendIndexTail) {m_nSendIndexTail = (m_nSendIndexTail + 1) % Sliding_Window_Size; //该结点已得到确认,将其加入旁视列表,以备再用::EnterCriticalSection(&m_csQueue);m_bufLookaside.push(m_bufqueue.front());m_bufqueue.pop();::LeaveCriticalSection(&m_csQueue);SetEvent(m_hEvent);}}接收端的接收线程:int ret;DWORD dwWritten;SendBuf recvbuf;RecvBuf sendbuf;// 设置文件指针位置,指向上次已发送的大小SetFilePointer(m_hFile, 0, NULL, FILE_END);//若已接收文件大小小于需要接收的大小,则继续while(m_dwSend < m_dwFileSize){//接收memset(&recvbuf, 0, sizeof(recvbuf));ret = m_hsocket.hrecvfrom((char*)&recvbuf, sizeof(recvbuf));if(ret == SOCKET_ERROR){return false;}//不是希望接收的,丢弃,继续接收if(recvbuf.index != (m_nRecvIndex) % Sliding_Window_Size){nerror++;cout << recvbuf.index << "error?" << m_nRecvIndex << endl; continue;}if(!WriteFile(m_hFile, recvbuf.buf, recvbuf.dwLen, &dwWritten, NULL)) {//AfxMessageBox("写入文件失败");cout << "写入文件失败" << endl;return false;}//已接收文件大小m_dwSend += dwWritten;//发送确认消息sendbuf.flag = Flag_Ack;sendbuf.index = m_nRecvIndex;ret = m_hsocket.hsendto((char*)&sendbuf, sizeof(sendbuf));if(ret == SOCKET_ERROR){return false;}//接收窗口前移一格m_nRecvIndex = (m_nRecvIndex + 1) % Sliding_Window_Size;}。