UDP文件传输

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 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);

//若不能整除,则应加1

if(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;

}

//延时,防止丢包

相关文档
最新文档