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_)