www.pudn.com > UDP文件传输.rar > HUDPCanal.h
// HUDPCanal.h: interface for the HUDPCanal class.
//
//////////////////////////////////////////////////////////////////////
#if !defined(AFX_HUDPCANAL_H__E4214D35_301E_46C0_992B_2F901B465F3C__INCLUDED_)
#define AFX_HUDPCANAL_H__E4214D35_301E_46C0_992B_2F901B465F3C__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
//////////////////////////////////////////////////////////////////////////////
//文件名 : HUDPCanal.h
//功能 : UDP通信通道,将自不同地址的UDP包分到不同的通道
//创建 : 2003.12.12
//修改日期 : 2004.11.14
//作者 : 韩国静
//
#include "HMutex.h"
#include "HList.h"
#include "HUdpSock.h"
#include "uni_time.h"
typedef struct st_hcanal{} *HCANAL;
typedef struct H_INET_ADDR{
UNI_DWORD dwIP;
UNI_WORD wPORT;
}H_CANAL_ID;
class HUDPCanal
{
CHMutex m_Mutex;
CHUdpSock m_sock;
typedef struct _stNode
{
H_INET_ADDR addr; //通道对方真正可用的地址
H_CANAL_ID canalId; //全局唯一的通道号,
UNI_DWORD dwMaxPackSize;
UNI_DWORD dwRef; //一个通道可能被多个任务占用,这是引用计数
UNI_DWORD dwRecvLen; //通道中现有数据的长度
void * pRecvData; //通道中现有的数据
UNI_DWORD dwTickCountO; //最后一次向此通道写出数据的系统时间
}CANALNODE,*PCANALNODE;
CHList m_Nodes;
protected:
// 在跨跃内外网的环境下,内网节点需要每隔一小段时间向对方发送一次数,以使NAT保持通道打开
// 此种情况下实际应重载此函数完成这一任务
virtual void ContinueConnect(HCANAL hcanal)
{
((PCANALNODE)hcanal)->dwTickCountO=UNI_GetTickCount();
};
// 默认的通道号是对方的IP和端口,但在跨跃内外网的环境下内网节点的IP和端口可能有变化。
// 此时可以由服务器分一个通道号并在数据包中传输,实际应用可以重载此函数从数据包中解析出真正的通道号!
virtual UNI_BOOL AnalyzieCanalID(void *cmd,UNI_DWORD dwCmdSize,UNI_DWORD realip,UNI_WORD realport,H_CANAL_ID &canalId)
{
canalId.dwIP=realip;
canalId.wPORT=realport;
return UNI_TRUE;
};
public:
//此函数允许应用动态修改通道的真实址址
static H_INET_ADDR *GetCanalAddr(HCANAL hcanal)
{
return &((PCANALNODE)hcanal)->addr;
}
static UNI_DWORD GetCanalPackSize(HCANAL hcanal)
{
return ((PCANALNODE)hcanal)->dwMaxPackSize;
}
static UNI_BOOL IsSameID(HCANAL hcanal,H_CANAL_ID &canalId)
{
H_CANAL_ID *id=&((PCANALNODE)hcanal)->canalId;
if(id->dwIP==canalId.dwIP && id->wPORT==canalId.wPORT)
return UNI_TRUE;
return UNI_FALSE;
}
UNI_BOOL Open(UNI_WORD port,UNI_DWORD dwIp)
{
m_Mutex.Lock();
m_Nodes.EmptyAll();
m_Mutex.UnLock();
return m_sock.CreateAt(port,dwIp);
}
void Close()
{
m_Mutex.Lock();
m_Nodes.EmptyAll();
m_Mutex.UnLock();
m_sock.Close();
}
//此处的ip和port是通道号而不是地址,但通道的初始地址与通道号相同
HCANAL CreateCanal(UNI_DWORD ip,UNI_WORD port)
{
CHList::HLISTPOSTION pos;
PCANALNODE pNode=UNI_NULL;
m_Mutex.Lock();
if(pos=m_Nodes.MoveToBegin())
{
while(pNode=m_Nodes.MoveToNext(pos))
{
if(pNode->canalId.dwIP==ip && pNode->canalId.wPORT==port)
break;
}
}
if(pNode==UNI_NULL)
{
if(pNode=m_Nodes.AddTail())
{
memset(pNode,0,sizeof(*pNode));
pNode->canalId.dwIP=ip;
pNode->addr.dwIP=ip;
pNode->canalId.wPORT=port;
pNode->addr.wPORT=port;
pNode->dwMaxPackSize=1024;
}
}
else
pNode->dwRef++;
m_Mutex.UnLock();
return (HCANAL)pNode;
}
void CloseCanal(HCANAL hcanal)
{
m_Mutex.Lock();
if(((PCANALNODE)hcanal)->dwRef)
((PCANALNODE)hcanal)->dwRef--;
else
{
if(((PCANALNODE)hcanal)->pRecvData)
delete (char*)((PCANALNODE)hcanal)->pRecvData;
m_Nodes.Remove((PCANALNODE)hcanal);
}
m_Mutex.UnLock();
}
//读出通道中的数据,同时数据被从通道中删除
UNI_DWORD ReadRecvedData(HCANAL hcanal,void **ppvoid)
{
PCANALNODE pNode;
UNI_DWORD len;
pNode=(PCANALNODE)hcanal;
len=0;
*ppvoid=UNI_NULL;
m_Mutex.Lock();
if(pNode->dwRecvLen)
{
*ppvoid=pNode->pRecvData;
len=pNode->dwRecvLen;
pNode->dwRecvLen=0;
pNode->pRecvData=UNI_NULL;
}
m_Mutex.UnLock();
return len;
}
//释放由ReadRecvedData返回数据内存
void ReleaseRecvedData(void **ppvoid)
{
if(*ppvoid)
delete (char *)(*ppvoid);
*ppvoid=UNI_NULL;
}
UNI_BOOL Send(HCANAL hcanal,void *pData,UNI_DWORD len)
{
PCANALNODE pNode;
pNode=(PCANALNODE)hcanal;
if(len==m_sock.SendTo(pData,len,pNode->addr.dwIP,pNode->addr.wPORT))
{
pNode->dwTickCountO=UNI_GetTickCount();
return UNI_TRUE;
}
return UNI_FALSE;
}
//等待某个通道有数据并返回这个通道
HCANAL ReadSelect(UNI_DWORD dwTimeOut/*等待时间ms*/,UNI_DWORD dwBufSize/*用来接收数据的最大缓冲内存*/)
{
char *pTemp;
H_CANAL_ID canalid;
UNI_DWORD dwIp,dwTickCount;
UNI_WORD wPort;
HCANAL ret;
PCANALNODE pNode;
CHList::HLISTPOSTION pos;
pTemp=UNI_NULL;
dwIp = 0;
ret=UNI_NULL;
m_Mutex.Lock();
if(pos=m_Nodes.MoveToBegin())
{
while(pNode=m_Nodes.MoveToNext(pos))
{
if(pNode->pRecvData!=UNI_NULL && pNode->dwRecvLen!=0)
{
ret=(HCANAL)pNode;
}
}
if(ret==UNI_NULL)
{
dwTickCount=UNI_GetTickCount();
while(dwTimeOut>0 && UNI_FALSE==m_sock.WaitForRead(dwTimeOut/1000,dwTimeOut%1000))
{
dwIp=dwTickCount;
dwTickCount=UNI_GetTickCount();
dwIp=dwTickCount-dwIp;
dwTimeOut>dwIp?dwTimeOut-=dwIp:dwTimeOut=0;
}
if(dwTimeOut!=0)//时间没用完表示收到了数据
{
if(pTemp=new char[dwBufSize])
{
if(dwBufSize=m_sock.RecvFrom(pTemp,dwBufSize,dwIp,wPort))
{
if(this->AnalyzieCanalID(pTemp,dwBufSize,dwIp,wPort,canalid))
{
//由上层负责从命令中计算发送者通道号
pos=m_Nodes.MoveToBegin();
while(pNode=m_Nodes.MoveToNext(pos))
{
if(pNode->canalId.wPORT==canalid.wPORT && pNode->canalId.dwIP==canalid.dwIP)
{
if(pNode->addr.wPORT!=wPort ||pNode->addr.dwIP!=dwIp)
{
pNode->addr.wPORT=wPort;
pNode->addr.dwIP=dwIp;
pNode->dwMaxPackSize=dwBufSize>1024?dwBufSize:1024;
}
else if(pNode->dwMaxPackSizedwMaxPackSize=dwBufSize;
}
if(pNode->pRecvData==UNI_NULL && pNode->dwRecvLen==0)
{
pNode->pRecvData=pTemp;
pNode->dwRecvLen=dwBufSize;
ret=(HCANAL)pNode;
pTemp=UNI_NULL;
}
}
if(dwTickCountdwTickCountO || dwTickCount - pNode->dwTickCountO >10000)//间隔10秒打洞一次
{
this->ContinueConnect((HCANAL)pNode);
}
}
}//
}
if(pTemp)
delete pTemp;
}
}
else
{
pos=m_Nodes.MoveToBegin();
while(pNode=m_Nodes.MoveToNext(pos))
{
if(dwTickCountdwTickCountO || dwTickCount - pNode->dwTickCountO >10000)//间隔10秒打洞一次
{
this->ContinueConnect((HCANAL)pNode);
}
}
}
}
}
m_Mutex.UnLock();
return ret;
}
//获取本地的IP和端口
UNI_DWORD GetLocal(UNI_OUT UNI_WORD &wPort)
{
UNI_DWORD ip;
ip=m_sock.GetLocal(wPort);
if(ip==0)
ip=m_sock.GetHostIp();
return ip;
}
HUDPCanal(){};
virtual ~HUDPCanal(){};
};
#endif // !defined(AFX_HUDPCANAL_H__E4214D35_301E_46C0_992B_2F901B465F3C__INCLUDED_)