200酬谢!
解决方案 »
- TTE字库
- windows画图板中的扭曲功能如何实现
- 多叉路口交通灯的管理 VC源程序
- 求助,ShockwaveFlash播放Flash,对话框背景图片每秒刷新3帧,flash闪烁厉害
- 我准备等下就跟老总说辞职的事,但有些顾虑,望大家指点指点,谢谢!!
- 如何取得BITMAPFILEHEADER和BITMAPINFOHEADER的值
- SQL SERVER 字符串的问题
- 菜鸟问题
- 关于打印时单位转换的问题(MM_TWIPS->MM_TEXT)
- 调用函数还有一个错,请各位指点.
- IIS加载我的Isapi DLL后,该DLL中的代码是作为系统权限运行还是作为其他用户权限运行?比如:
- 基于FTP协议的通信程序源码!
其实使用udp进行文件传输最好得用途是在一对多才有效率,否则还是用tcp
[email protected]
谢谢!
RUDPHeader.h#include <assert.h>
#include <Easiware/RUDP/Type.h>
#include <Easiware/RUDP/Flag.h>namespace Easiware{namespace RUDP
{
const int MAX_PACKET_SIZE = 16384; //16K #pragma pack(1)
struct RUDPHeader
{
public:
uint16 Flags;
uint16 DataLen;
uint32 SEQNumber;
uint32 ACKNumber;
uint32 CheckSum;
public:
RUDPHeader(uint16 nFlags = 0, uint16 nLen = 0, uint32 nSeq = 0, uint32 nAck = 0, uint32 nSum = 0)
: Flags(nFlags), DataLen(nLen), SEQNumber(nSeq), ACKNumber(nAck), CheckSum(nSum)
{} RUDPHeader(const void* pBuffer, size_t nBufferSize)
{
if (nBufferSize > sizeof(RUDPHeader))
nBufferSize = sizeof(RUDPHeader);
memcpy(this, pBuffer, nBufferSize);
}
};
#pragma pack()
}} // namespace Easiware
Type.hnamespace Easiware{namespace RUDP
{
typedef unsigned short uint16;
typedef unsigned long uint32;
}} // namespace Easiware
Flag.h
//暂无定义
#include <afxsock.h>
#include <Easiware/RUDP/RUDPHeader.h>
#include <Easiware/Memory/DataChunk.h>
#include <Easiware/Net/SocketException.h>
namespace Easiware{namespace RUDP
{
namespace MFC
{
/// RUDP:Reliable UDP,基于UDP实现了可靠的传输
class CRUDPSocket : public CSocket
{
private:
using CSocket::Accept;
using CSocket::Bind;
using CSocket::Connect;
using CSocket::Listen;
using CSocket::Receive;
using CSocket::ReceiveFrom;
using CSocket::Send;
using CSocket::SendTo;
using CSocket::Create; protected: // SendingData
struct SendingData
{
public:
RUDPHeader Header;
Memory::CDataChunk Packet;
sockaddr_in Target;
public:
SendingData(const RUDPHeader& header, const Memory::CDataChunk& packet, const sockaddr_in& saTarget)
: Header(header), Packet(packet), Target(saTarget)
{}
};
typedef std::map<uint32, SendingData> SendingDataMap; protected: // ReceivedData
struct ReceivedData
{
public:
RUDPHeader Header;
Memory::CDataChunk Payload;
sockaddr_in Sender;
public:
ReceivedData(const RUDPHeader& header, const Memory::CDataChunk& data, const sockaddr_in& saSender)
: Header(header), Payload(data), Sender(saSender)
{}
};
typedef std::map<uint32, ReceivedData> ReceivedDataMap; public:
CRUDPSocket()
: m_nRetryCount(1)
, m_nTimeOut(6000)
{}
virtual ~CRUDPSocket() {} public:
/// 创建Socket并绑定端口,开始侦听
void CreateSocket(unsigned short nPort = 0); /// 发送数据(要求接收方发送响应包), 返回接受到的回应包
ReceivedData SendPacket(const void* pBuf, int nBufLen, const sockaddr_in& saTarget, uint32 nAck = 0, uint16 nFlags = 0, bool bAutoACK = true, long nTimeout = 0); /// 发送单向数据(不要求接收方发送响应包)
void SendUniPacket(const void* pBuf, int nBufLen, const sockaddr_in& saTarget, uint32 nAck = 0, uint16 nFlags = 0); void SendACKPacket(const sockaddr_in& saTarget, uint32 nAck = 0, uint16 nFlags = 0); public:
long GetRetryCount() const { return m_nRetryCount; }
void SetRetryCount(long v) { m_nRetryCount = v; } /// in milliseconds
long GetTimeout() const { return m_nTimeOut; }
void SetTimeout(long v) { m_nTimeOut = v; } private: // implements of CSocket
virtual void OnReceive(int nErrorCode); protected: // virtual functions
virtual void _OnReceivePacket(ReceivedData& data) = 0;
virtual void _OnReceiveError(const TCHAR* szErr); protected:
SendingData& _GetSendingData(uint32 nSeq); ReceivedData& _PeekReceivedData(uint32 nSeq);
ReceivedData _PopReceivedData(uint32 nSeq); void _SendDataOnly(const void* pBuf, int nBufLen, const sockaddr_in& saTarget); private:
uint32 _GetAvailableSEQ() const;
bool _IsSEQExists(uint32 nSeq) const; bool _IsACKReceived(uint32 nSeq) const; void _WaitForReply(const SendingData& info, long nTimeout);
protected:
SendingDataMap m_mapSending;
ReceivedDataMap m_mapReceived; private:
long m_nTimeOut;
long m_nRetryCount;
};
}
}} // namespace Easiware
#include <Easiware/RUDP/MFC/RUDPSocket.h>
#include <Easiware/Win32/SystemEx.h>#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endifnamespace Easiware{namespace RUDP
{
namespace MFC
{
void CRUDPSocket::CreateSocket(unsigned short nPort)
{
if (!CSocket::Create(nPort, SOCK_DGRAM))
{
throw Net::CSocketException(_T("无法创建Socket!"));
}
} CRUDPSocket::ReceivedData CRUDPSocket::SendPacket(const void* pBuf, int nBufLen, const sockaddr_in& saTarget, uint32 nAck, uint16 nFlags, bool bAutoACK, long nTimeout)
{
// 发包
uint32 nSeq = _GetAvailableSEQ();
RUDPHeader header(nFlags, nBufLen, nSeq, nAck, 0);
Memory::CDataChunk packet(&header, sizeof(RUDPHeader));
packet.AppendWithoutLen(pBuf, nBufLen);
_SendDataOnly(packet.Data(), packet.Size(), saTarget); // 等待回复
_WaitForReply(SendingData(header, packet, saTarget), nTimeout); // 如果需要,发送自动回复包
ReceivedData& ack = _PeekReceivedData(nSeq);
if ( bAutoACK && (ack.Header.SEQNumber > 0) )
SendACKPacket(ack.Sender, ack.Header.SEQNumber); // 返回接收到的数据
return _PopReceivedData(nSeq);
} void CRUDPSocket::SendUniPacket(const void* pBuf, int nBufLen, const sockaddr_in& saTarget, uint32 nAck, uint16 nFlags)
{
// 发包
RUDPHeader header(nFlags, nBufLen, 0, nAck, 0);
Memory::CDataChunk packet(&header, sizeof(RUDPHeader));
packet.AppendWithoutLen(pBuf, nBufLen);
_SendDataOnly(packet.Data(), packet.Size(), saTarget);
} void CRUDPSocket::SendACKPacket(const sockaddr_in& saTarget, uint32 nAck, uint16 nFlags)
{
SendUniPacket(NULL, 0, saTarget, nAck, 0);
}
void CRUDPSocket::OnReceive(int nErrorCode)
{
if (nErrorCode == WSAENETDOWN)
{
_OnReceiveError(_T("接受数据时发生错误!"));
return;
} // 收包
char szBuffer[MAX_PACKET_SIZE] = "";
sockaddr_in saSender;
int nTmp = sizeof(sockaddr_in);
int nReceived = CSocket::ReceiveFrom(szBuffer, MAX_PACKET_SIZE, (sockaddr*)&saSender, &nTmp);
if (nReceived == SOCKET_ERROR)
{
_OnReceiveError(_T("接受数据时发生错误!"));
return;
} // 分析得到报头、数据
RUDPHeader header(szBuffer, sizeof(RUDPHeader));
ReceivedData data(header,
Memory::CDataChunk(szBuffer + sizeof(RUDPHeader), nReceived - sizeof(RUDPHeader)),
saSender); // 如果需要,写入接收队列
uint32 nAck = header.ACKNumber;
if ((nAck > 0) && _IsSEQExists(nAck))
{
m_mapReceived.insert( ReceivedDataMap::value_type(nAck, data) );
}
else
_OnReceivePacket(data);
} void CRUDPSocket::_OnReceiveError(const TCHAR* szErr)
{
// do nothing
} void CRUDPSocket::_WaitForReply(const SendingData& info, long nTimeout)
{
const int CHECK_INTERVAL = 200;
if (nTimeout == 0) nTimeout = m_nTimeOut; // 取得 Sequence Number
uint32 nSeq = info.Header.SEQNumber; // 写入发送队列
m_mapSending.insert( SendingDataMap::value_type(nSeq, info) );
// 这里实现了重试机制
int nMax = ( nTimeout / CHECK_INTERVAL );
for (int i=0; i < m_nRetryCount; ++i)
{
// 轮询等待接受到ACK包
for (int j=0; j < nMax; ++j)
{
if (_IsACKReceived(nSeq)) return; ::Sleep(CHECK_INTERVAL);
Easiware::Win32::CSystemEx::DoEvents();
} // 如果没有成功,重新发包,再次尝试
SendingData& data = _GetSendingData(nSeq);
_SendDataOnly(data.Packet.Data(), data.Packet.Size(), data.Target);
} // 没有收到ACK包,只好将该包从发送队列中删除,并报告错误
m_mapSending.erase(nSeq);
throw Net::CSocketTimeoutException();
} // 确保得到不重复的Sequence Number
uint32 CRUDPSocket::_GetAvailableSEQ() const
{
for (uint32 nSeq=1; _IsSEQExists(nSeq) || _IsACKReceived(nSeq); ++nSeq);
return nSeq;
} // 判断当前是否已经存在指定的Sequence Number
bool CRUDPSocket::_IsSEQExists(uint32 nSeq) const
{
return ( m_mapSending.find(nSeq) != m_mapSending.end() );
} // 判断是否已经收到ACK包
bool CRUDPSocket::_IsACKReceived(uint32 nSeq) const
{
return ( m_mapReceived.find(nSeq) != m_mapReceived.end() );
} CRUDPSocket::SendingData& CRUDPSocket::_GetSendingData(uint32 nSeq)
{
SendingDataMap::iterator it = m_mapSending.find(nSeq);
return it->second;
} CRUDPSocket::ReceivedData& CRUDPSocket::_PeekReceivedData(uint32 nSeq)
{
ReceivedDataMap::iterator it = m_mapReceived.find(nSeq);
return it->second;
} CRUDPSocket::ReceivedData CRUDPSocket::_PopReceivedData(uint32 nSeq)
{
CRUDPSocket::ReceivedData data(_PeekReceivedData(nSeq)); m_mapSending.erase(nSeq);
m_mapReceived.erase(nSeq); return data;
} void CRUDPSocket::_SendDataOnly(const void* pBuf, int nBufLen, const sockaddr_in& saTarget)
{
int nSended = CSocket::SendTo(pBuf, nBufLen, (const sockaddr*)&saTarget, sizeof(sockaddr));
if (nSended == SOCKET_ERROR)
throw Net::CSocketException(_T("发送数据时发生错误!"));
} }
}} // namespace Easiware