首页 > 代码库 > Android RakNet 系列之六 源码说明

Android RakNet 系列之六 源码说明

简介

既然选择Raknet开发,那就深入研究其源码结构,为以后的应用打下基础。

详情

1、文件

文件 描述
_FindFirst快速查找
AutopatcherPatchContext自动更新、不停
AutopatcherRepositoryInterface更新 获取重要的数据接口
Base64Encoderbase64编码
BitStream比特流 流结构
CCRakNetSlidingWindow观测
CCRakNetUDT 
CheckSum校验
CloudClient云端 客户端
CloudCommon云端 通用功能
CloudServer云端 服务器
CommandParserInterface通用解析接口
ConnectionGraph2连接图
ConsoleServer控制服务器
DataCompressor数据处理
DirectoryDeltaTransfer文件目录传输
DR_SHA1哈希值计算
DS_BinarySearchTree二叉树查询
DS_BPlusTree二叉树
DS_BytePool字节池
DS_ByteQueue字节队列
DS_Hash哈希
DS_Heap堆栈
DS_HuffmanEncodingTree哈夫曼编码树
DS_HuffmanEncodingTreeFactory哈夫曼编码树产生
DS_HuffmanEncodingTreeNode哈夫曼编码树节点
DS_LinkedList链表
DS_List列表
DS_Map哈希
DS_MemoryPool内存池
DS_Multilist多链表
DS_OrderedChannelHeap顺序通道堆
DS_OrderedList有序列表
DS_Queue队列
DS_QueueLinkedList队列链表
DS_RangeList范围列表
DS_Table
DS_ThreadsafeAllocatingQueue线性安全队列
DS_Tree
DS_WeightedGraph权重图
DynDNS动态域
EmailSender邮箱发送
EmptyHeader 
EpochTimeToString时间值转换
Export导出
FileList文件列表
FileListNodeContext文件列表节点
FileListTransfer文件列表传输
FileListTransferCBInterface文件列表传输接口
FileOperations文件操作
FormatString字符格式化
FullyConnectedMesh2饱和链接
Getche获取一个字符
Gets获取一组字符
GetTime获取时间
gettimeofday获取一天的时间值
GridSectorizer.h网格
HTTPConnectionhttp连接类
HTTPConnection2http连接插件类
IncrementalReadInterface 
InternalPacket内部包
Itoa整形转换
Kbhit单击
LinuxStrings 
LocklessTypes计数
LogCommandParser日志分析
MessageFilter.h消息过滤
MessageIdentifiers消息id
MTUSize定义默认的最大、最小传输单元
NativeFeatureIncludes定义本地功能
NativeFeatureIncludesOverrides 
NativeTypes本地类型
NatPunchthroughClient穿透插件
NatPunchthroughServer穿透服务器
NatTypeDetectionClient网络类型匹配
NatTypeDetectionCommon网络类型匹配 通用
NatTypeDetectionServer网络类型匹配服务端
NetworkIDManager网络id管理
NetworkIDObject网络id对象
PacketConsoleLogger包控制日志
PacketFileLogger包日志记录
PacketizedTCPtcp包分组
PacketLogger包记录
PacketOutputWindowLogger包输出记录
PacketPool 
PacketPriority枚举枚举分组优先级和可靠性
PluginInterface2插件接口
PS3Includes 
PS4Includes 
Rackspace辅助服务器空间
RakAlloca内存申请
RakAssert 
RakMemoryOverride内存管理
RakNetCommandParser通用解析
RakNetDefines定义
RakNetDefinesOverrides 
RakNetSmartPtr引用指针
RakNetSocket套接字
RakNetSocket2套接字2
RakNetStatistics常量
RakNetTime时间
RakNetTransport2传输端口
RakNetTypes使用网络类型
RakNetVersion版本
RakPeer实例
RakPeerInterface 
RakSleep 
RakString 
RakThread 
RakWString 
Rand 
RandSync 
ReadyEvent 
RefCountedObj引用计数
RelayPlugin延迟插件
ReliabilityLayer数据层
ReplicaEnums复制管理系统
ReplicaManager3复制管理
Router2路由器插件
RPC4Plugin远程调用call插件
SecureHandshake密钥握手
SendToThread 
SignaledEvent信号事件
SimpleMutex互斥
SimpleTCPServer 
SingleProducerConsumer通过使用一个循环缓冲区队列中读写指针线程之间的数据
SocketDefines 
SocketIncludes套接字包含
SocketLayer套接字层
StatisticsHistory统计记录(输入的数值和时间)
StringCompressor字符串压缩
StringTable字符串编码与解码
SuperFastHash 
TableSerializer 
TCPInterfacetcp操作接口
TeamBalancer团队平衡
TeamManager团队管理
TelnetTransport传输
ThreadPool线程池
ThreadsafePacketLogger线性安全数据包 日志
TransportInterface传输接口
TwoWayAuthentication双向认证
UDPForwarderudp数据包
UDPProxyClientudp代理客户端
UDPProxyCommon 
UDPProxyCoordinator代理协调
UDPProxyServer代理服务器
VariableDeltaSerializer变量序列化
VariableListDeltaTracker变量监听
VariadicSQLParser变量sql分析
VitaIncludes 
WindowsIncludes 
WSAStartupSingleton 
XBox360Includes 
  


2、功能分类
1、编码辅助

编码有关的文件如:

Base64Encoder、DR_SHA1、DS_HuffmanEncodingTree、DS_HuffmanEncodingTreeFactory、DS_HuffmanEncodingTreeNode


其中Base64Encoder提供两个函数

extern "C" {
/// \brief Returns how many bytes were written.
// outputData should be at least the size of inputData * 2 + 6
int Base64Encoding(const unsigned char *inputData, int dataLength, char *outputData);
}

extern "C" {
const char *Base64Map(void);
}


DR_SHA1用于数字签名标准,测试如下:

  SHA1("abc" in ANSI) =
    A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
  SHA1("abc" in Unicode LE) =
    9F04F41A 84851416 2050E3D6 8C1A7ABB 441DC2B5

  SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
    in ANSI) =
    84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
  SHA1("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
    in Unicode LE) =
    51D7D876 9AC72C40 9C5B0E3F 69C60ADC 9A039014

  SHA1(A million repetitions of "a" in ANSI) =
    34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
  SHA1(A million repetitions of "a" in Unicode LE) =
    C4609560 A108A0C6 26AA7F2B 38A65566 739353C5

DS_HuffmanEncodingTree、DS_HuffmanEncodingTreeFactory、DS_HuffmanEncodingTreeNode跟哈夫曼有关。

哈夫曼编码(Huffman Coding)是一种编码方式,哈夫曼编码是可变字长编码(VLC)的一种。Huffman于1952年提出一种编码方法,该方法完全依据字符出现概率来构造异字头的平均长度最短的码字,有时称之为最佳编码,一般就叫做Huffman编码(有时也称为霍夫曼编码)。

节点结构如下:

struct HuffmanEncodingTreeNode
{
	unsigned char value;
	unsigned weight;
	HuffmanEncodingTreeNode *left;
	HuffmanEncodingTreeNode *right;
	HuffmanEncodingTreeNode *parent;
};


2、容器辅助

容器可以管理对象的生命周期、对象与对象之间的依赖关系,您可以使用一个配置文件(通常是XML),在上面定义好对象的名称、如何产生(Prototype 方式或Singleton 方式)、哪个对象产生之后必须设定成为某个对象的属性等,在启动容器之后,所有的对象都可以直接取用,不用编写任何一行程序代码来产生对象,或是建立对象与对象之间的依赖关系。

容器分同步异步、线程安全非安全之分。

跟容器相关的文件如下:

DS_BinarySearchTree、DS_BPlusTree、DS_Hash、DS_Heap、DS_LinkedList、DS_List、DS_Map、DS_Multilist、DS_OrderedChannelHeap

DS_OrderedList、DS_Queue、DS_QueueLinkedList、DS_RangeList、DS_ThreadsafeAllocatingQueue、DS_Tree


DS_BinarySearchTree :二叉搜索树:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

* EXAMPLE
	 * @code
	 * BinarySearchTree<int> A;
	 * A.Add(10);
	 * A.Add(15);
	 * A.Add(5);
	 * int* array = RakNet::OP_NEW<int >(A.Size(), _FILE_AND_LINE_ );
	 * A.DisplayInorder(array);
	 * array[0]; // returns 5
	 * array[1]; // returns 10
	 * array[2]; // returns 15

DS_BPlusTree

二叉树:每个结点最多有两个子树的有序树。

void main(void)
{
	DataStructures::BPlusTree<int, int, 16> btree;
	DataStructures::List<int> haveList, removedList;
	int temp;
	int i, j, index;
	int testSize;
	bool b;

	for (testSize=0; testSize < 514; testSize++)
	{
		RAKNET_DEBUG_PRINTF("TestSize=%i\n", testSize);

		for (i=0; i < testSize; i++)
			haveList.Insert(i);

		for (i=0; i < testSize; i++)
		{
			index=i+randomMT()%(testSize-i);
			temp=haveList[index];
			haveList[index]=haveList[i];
			haveList[i]=temp;
		}

		for (i=0; i<testSize; i++)
		{
			btree.Insert(haveList[i], haveList[i]);
			btree.ValidateTree();
		}

		for (i=0; i < testSize; i++)
		{
			index=i+randomMT()%(testSize-i);
			temp=haveList[index];
			haveList[index]=haveList[i];
			haveList[i]=temp;
		}
		for (i=0; i<testSize; i++)
		{
			btree.Delete(haveList[0]); // Asserts on 8th call.  Fails on going to remove 8 (7th call)
			removedList.Insert(haveList[0]);
			haveList.RemoveAtIndex(0);
			for (j=0; j < removedList.Size(); j++)
			{
				b=btree.Get(removedList[j], temp);
				RakAssert(b==false);
			}
			for (j=0; j < haveList.Size(); j++)
			{
				b=btree.Get(haveList[j], temp);
				RakAssert(b==true);
				RakAssert(haveList[j]==temp);
			}
			RakAssert(btree.Size()==haveList.Size());
			btree.ValidateTree();
		}
		btree.Clear(_FILE_AND_LINE_);
		removedList.Clear(_FILE_AND_LINE_);
		haveList.Clear(_FILE_AND_LINE_);
	}

	RAKNET_DEBUG_PRINTF("Done. %i\n", btree.Size());
	char ch[256];
	Gets(ch, sizeof(ch));
}


DS_Hash:把任意长度的输入(预映射)通过散列算法变换成固定长度的输出,该输出就是散列值。

//直接取余法:f(x):= x mod maxM ; maxM一般是不太接近 2^t 的一个质数。
//乘法取整法:f(x):=trunc((x/maxX)*maxlongit) mod maxM,主要用于实数。
//平方取中法:f(x):=(x*x div 1000 ) mod 1000000); 平方后取中间的,每位包含信息比较多。
项目中结构体:

	struct HashIndex
	{
		unsigned int primaryIndex;
		unsigned int secondaryIndex;
		bool IsInvalid(void) const {return primaryIndex==(unsigned int) -1;}
		void SetInvalid(void) {primaryIndex=(unsigned int) -1; secondaryIndex=(unsigned int) -1;}
	};

DS_Heap

堆:一种特殊的树形数据结构,它满足堆的特性:父节点的值一定大于或等于子节点的值。

		struct HeapNode
		{
			HeapNode() {}
			HeapNode(const weight_type &w, const data_type &d) : weight(w), data(d) {}
			weight_type weight; // I‘m assuming key is a native numerical type - float or int
			data_type data;
		};

DS_OrderedChannelHeap:同上


DS_LinkedList:链表:

	* EXAMPLE:
	* @code
	* LinkedList<int> A;  // Creates a Linked List of integers called A
	* CircularLinkedList<int> B;  // Creates a Circular Linked List of 
	*          // integers called B
	*
	* A.Insert(20);  // Adds 20 to A.  A: 20 - current is 20
	* A.Insert(5);  // Adds 5 to A.  A: 5 20 - current is 5
	* A.Insert(1);  // Adds 1 to A.  A: 1 5 20 - current is 1
	*
	* A.IsIn1); // returns true
	* A.IsIn200); // returns false
	* A.Find(5);  // returns true and sets current to 5
	* A.Peek();  // returns 5
	* A.Find(1);  // returns true and sets current to 1
	*
	* (++A).Peek();  // Returns 5
	* A.Peek(); // Returns 5
	*
	* A.Replace(10);  // Replaces 5 with 10.
	* A.Peek();  // Returns 10
	*
	* A.Beginning();  // Current points to the beginning of the list at 1
	*
	* (++A).Peek();  // Returns 5
	* A.Peek();  // Returns 10
	*
	* A.Del();  // Deletes 10.  Current points to the next element, which is 20
	* A.Peek();  // Returns 20
	* 
	* A.Beginning();  // Current points to the beginning of the list at 1
	*
	* (++A).Peek();  // Returns 5
	* A.Peek();  // Returns 20
	*
	* A.Clear(_FILE_AND_LINE_);  // Deletes all nodes in A
	*
	* A.Insert(5);  // A: 5 - current is 5
	* A.Insert(6); // A: 6 5 - current is 6
	* A.Insert(7); // A: 7 6 5 - current is 7
	*
	* A.Clear(_FILE_AND_LINE_);
	* B.Clear(_FILE_AND_LINE_);
	*
	* B.Add(10);
	* B.Add(20);
	* B.Add(30);
	* B.Add(5);
	* B.Add(2);
	* B.Add(25);
	* // Sorts the numbers in the list and sets the current pointer to the 
	* // first element
	* B.sort();  
	*
	* // Postfix ++ just calls the prefix version and has no functional 
	* // difference.
	* B.Peek();  // Returns 2
	* B++;
	* B.Peek();  // Returns 5
	* B++;
	* B.Peek();  // Returns 10
	* B++;
	* B.Peek();  // Returns 20
	* B++;
	* B.Peek();  // Returns 25
	* B++;
	* B.Peek();  // Returns 30

DS_List、DS_Multilist、DS_OrderedList、DS_RangeList、DS_QueueLinkedList:同上

DS_Map:键值对

		lastSearchIndex=index;
		lastSearchKey=key;
		lastSearchIndexValid=true;

结构体:

		struct MapNode
		{
			MapNode() {}
			MapNode(key_type _key, data_type _data) : mapNodeKey(_key), mapNodeData(_data) {}
			MapNode& operator = ( const MapNode& input ) {mapNodeKey=input.mapNodeKey; mapNodeData=http://www.mamicode.com/input.mapNodeData; return *this;}>

DS_Queue:队列,先进后出的原则。

DS_ThreadsafeAllocatingQueue:同上,特点是在线程中是安全的,应该添加了锁。

DS_Tree:树结构

类如下:

	template <class TreeType>
	class RAK_DLL_EXPORT Tree
	{
	public:
		Tree();
		Tree(TreeType &inputData);
		~Tree();
		void LevelOrderTraversal(DataStructures::List<Tree*> &output);
		void AddChild(TreeType &newData);
		void DeleteDecendants(void);

		TreeType data;
		DataStructures::List<Tree *> children;
	};

3、字节辅助

字节辅助操作相关的文件有:

DS_BytePool、DS_ByteQueue

DS_BytePool:字节池,有效管理字节,主要是申请内存和释放。

类如下:

	class RAK_DLL_EXPORT BytePool
	{
	public:
		BytePool();
		~BytePool();
		// Should be at least 8 times bigger than 8192
		void SetPageSize(int size);
		unsigned char* Allocate(int bytesWanted, const char *file, unsigned int line);
		void Release(unsigned char *data, const char *file, unsigned int line);
		void Clear(const char *file, unsigned int line);
	protected:	
		MemoryPool<unsigned char[128]> pool128;
		MemoryPool<unsigned char[512]> pool512;
		MemoryPool<unsigned char[2048]> pool2048;
		MemoryPool<unsigned char[8192]> pool8192;
#ifdef _THREADSAFE_BYTE_POOL
		SimpleMutex mutex128;
		SimpleMutex mutex512;
		SimpleMutex mutex2048;
		SimpleMutex mutex8192;
#endif
	};
DS_ByteQueue:字节队列,字节写入和读取的操作。

类如下:

	class ByteQueue
	{
	public:
		ByteQueue();
		~ByteQueue();
		void WriteBytes(const char *in, unsigned length, const char *file, unsigned int line);
		bool ReadBytes(char *out, unsigned maxLengthToRead, bool peek);
		unsigned GetBytesWritten(void) const;
		char* PeekContiguousBytes(unsigned int *outLength) const;
		void IncrementReadOffset(unsigned length);
		void DecrementReadOffset(unsigned length);
		void Clear(const char *file, unsigned int line);
		void Print(void);

	protected:
		char *data;
		unsigned readOffset, writeOffset, lengthAllocated;
	};

4、字符串辅助

字节辅助操作相关的文件有:

FormatString、LinuxStrings、RakString、RakWString、StringCompressor、StringTable、EpochTimeToString

顾名思义,操作字符串的类或函数。

FormatString:

extern "C" { //格式化输出
char * FormatString(const char *format, ...);
}
// Threadsafe
extern "C" {
char * FormatStringTS(char *output, const char *format, ...);
}
LinuxStrings:系统函数

#if  defined(__native_client__)
	#ifndef _stricmp
		int _stricmp(const char* s1, const char* s2);
	#endif
	int _strnicmp(const char* s1, const char* s2, size_t n);
	char *_strlwr(char * str );
	#define _vsnprintf vsnprintf
#else
 #if (defined(__GNUC__)  || defined(__GCCXML__) || defined(__S3E__) ) && !defined(_WIN32)
		#ifndef _stricmp
			int _stricmp(const char* s1, const char* s2);
		#endif 
		int _strnicmp(const char* s1, const char* s2, size_t n);
		// http://www.jenkinssoftware.com/forum/index.php?topic=5010.msg20920#msg20920
     //   #ifndef _vsnprintf
		    #define _vsnprintf vsnprintf
       // #endif
#ifndef __APPLE__
		char *_strlwr(char * str ); //this won‘t compile on OSX for some reason
#endif
RakString、RakWString:自定义的字符串,添加很多操作符。

StringCompressor:字符串压缩

把文件流压缩成字符串或字符串编程文件流等操作。

哈夫曼编码树管理

	/// Pointer to the huffman encoding trees.
	DataStructures::Map<int, HuffmanEncodingTree *> huffmanEncodingTrees;

StringTable:字符串编码与解码

int RAK_DLL_EXPORT StrAndBoolComp( char *const &key, const StrAndBool &data );

EpochTimeToString:时间值转换

RAK_DLL_EXPORT char * EpochTimeToString(long long time);


5、内存辅助

RakNetSmartPtr、RakAlloca、RakAssert、RakMemoryOverride

有效管理内存或指针。

RakNetSmartPtr:实现对指针的管理。

关键类:

class RAK_DLL_EXPORT ReferenceCounter
{
private:
	int refCount;

public:
	ReferenceCounter() {refCount=0;}
	~ReferenceCounter() {}
	void AddRef() {refCount++;}
	int Release() {return --refCount;}
	int GetRefCount(void) const {return refCount;}
};

RakAlloca、RakAssert、RakMemoryOverride:实现内存的管理

RakAlloca、RakAssert :直接引用系统函数。

RakMemoryOverride:对外公开接口,如下:

extern RAK_DLL_EXPORT void * (*rakMalloc) (size_t size);
extern RAK_DLL_EXPORT void * (*rakRealloc) (void *p, size_t size);
extern RAK_DLL_EXPORT void (*rakFree) (void *p);
extern RAK_DLL_EXPORT void * (*rakMalloc_Ex) (size_t size, const char *file, unsigned int line);
extern RAK_DLL_EXPORT void * (*rakRealloc_Ex) (void *p, size_t size, const char *file, unsigned int line);
extern RAK_DLL_EXPORT void (*rakFree_Ex) (void *p, const char *file, unsigned int line);
extern RAK_DLL_EXPORT void (*notifyOutOfMemory) (const char *file, const long line);
extern RAK_DLL_EXPORT void * (*dlMallocMMap) (size_t size);
extern RAK_DLL_EXPORT void * (*dlMallocDirectMMap) (size_t size);
extern RAK_DLL_EXPORT int (*dlMallocMUnmap) (void* ptr, size_t size);

// Change to a user defined allocation function
void RAK_DLL_EXPORT SetMalloc( void* (*userFunction)(size_t size) );
void RAK_DLL_EXPORT SetRealloc( void* (*userFunction)(void *p, size_t size) );
void RAK_DLL_EXPORT SetFree( void (*userFunction)(void *p) );
void RAK_DLL_EXPORT SetMalloc_Ex( void* (*userFunction)(size_t size, const char *file, unsigned int line) );
void RAK_DLL_EXPORT SetRealloc_Ex( void* (*userFunction)(void *p, size_t size, const char *file, unsigned int line) );
void RAK_DLL_EXPORT SetFree_Ex( void (*userFunction)(void *p, const char *file, unsigned int line) );
// Change to a user defined out of memory function
void RAK_DLL_EXPORT SetNotifyOutOfMemory( void (*userFunction)(const char *file, const long line) );
void RAK_DLL_EXPORT SetDLMallocMMap( void* (*userFunction)(size_t size) );
void RAK_DLL_EXPORT SetDLMallocDirectMMap( void* (*userFunction)(size_t size) );
void RAK_DLL_EXPORT SetDLMallocMUnmap( int (*userFunction)(void* ptr, size_t size) );

extern RAK_DLL_EXPORT void * (*GetMalloc()) (size_t size);
extern RAK_DLL_EXPORT void * (*GetRealloc()) (void *p, size_t size);
extern RAK_DLL_EXPORT void (*GetFree()) (void *p);
extern RAK_DLL_EXPORT void * (*GetMalloc_Ex()) (size_t size, const char *file, unsigned int line);
extern RAK_DLL_EXPORT void * (*GetRealloc_Ex()) (void *p, size_t size, const char *file, unsigned int line);
extern RAK_DLL_EXPORT void (*GetFree_Ex()) (void *p, const char *file, unsigned int line);
extern RAK_DLL_EXPORT void *(*GetDLMallocMMap())(size_t size);
extern RAK_DLL_EXPORT void *(*GetDLMallocDirectMMap())(size_t size);
extern RAK_DLL_EXPORT int (*GetDLMallocMUnmap())(void* ptr, size_t size);
6、其它辅助

_FindFirst、CheckSum、RefCountedObj、ThreadPool、DS_Table、Getche、Gets、GetTime、gettimeofday、Itoa

Kbhit、LocklessTypes、RakNetTime、RakThread、

这些都是辅助项目的函数或类。、


_FindFirst:文件快速查找

long _findfirst(const char *name, _finddata_t *f);
int _findnext(long h, _finddata_t *f);
int _findclose(long h);

SuperFastHash:快速哈希

对外的接口如下:

uint32_t SuperFastHash (const char * data, int length);
uint32_t SuperFastHashIncremental (const char * data, int len, unsigned int lastHash );
uint32_t SuperFastHashFile (const char * filename);
uint32_t SuperFastHashFilePtr (FILE *fp);

CheckSum:效验和

类如下:

class CheckSum
{

public:
	
 /// Default constructor
	
	CheckSum()
	{
		Clear();
	}
	
	void Clear()
	{
		sum = 0;
		r = 55665;
		c1 = 52845;
		c2 = 22719;
	}
	
	void Add ( unsigned int w );
	
	
	void Add ( unsigned short w );
	
	void Add ( unsigned char* b, unsigned int length );
	
	void Add ( unsigned char b );
	
	unsigned int Get ()
	{
		return sum;
	}
	
protected:
	unsigned short r;
	unsigned short c1;
	unsigned short c2;
	unsigned int sum;
};

RefCountedObj、LocklessTypes:引用计数

实现对对象生命周期的管理,类如下:

class RAK_DLL_EXPORT LocklessUint32_t
{
public:
	LocklessUint32_t();
	explicit LocklessUint32_t(uint32_t initial);
	// Returns variable value after changing it
	uint32_t Increment(void);
	// Returns variable value after changing it
	uint32_t Decrement(void);
	uint32_t GetValue(void) const {return value;}

protected:
#ifdef _WIN32
	volatile LONG value;
#elif defined(ANDROID) || defined(__S3E__) || defined(__APPLE__)
	// __sync_fetch_and_add not supported apparently
	SimpleMutex mutex;
	uint32_t value;
#else
	volatile uint32_t value;
#endif
};
class RefCountedObj
{
	public:
		RefCountedObj() {refCount=1;}
		virtual ~RefCountedObj() {}
		void AddRef(void) {refCount++;}
		void Deref(void) {if (--refCount==0) RakNet::OP_DELETE(this, _FILE_AND_LINE_);}
		int refCount;
};

ThreadPool、RakThread:实现对线程的管理和封装

Getche、Gets、GetTime、gettimeofday、Itoa、Kbhit、RakNetTime:系统函数

DS_Table:实现对数据库表的 操作

7、消息id(内部消息id和用户自定义消息id)

enum OutOfBandIdentifiers
{
	ID_NAT_ESTABLISH_UNIDIRECTIONAL, //单向穿透
	ID_NAT_ESTABLISH_BIDIRECTIONAL, //双向穿透
	ID_NAT_TYPE_DETECT, //匹配类型
	ID_ROUTER_2_REPLY_TO_SENDER_PORT, //路由器延时发送端口
	ID_ROUTER_2_REPLY_TO_SPECIFIED_PORT, //特定端口
	ID_ROUTER_2_MINI_PUNCH_REPLY, //回复
	ID_ROUTER_2_MINI_PUNCH_REPLY_BOUNCE, //反弹
	ID_XBOX_360_VOICE, //声音
	ID_XBOX_360_GET_NETWORK_ROOM, //获取网络房间
	ID_XBOX_360_RETURN_NETWORK_ROOM, //返回网络房间
	ID_NAT_PING, //ping测试
	ID_NAT_PONG, //pong测试
};

枚举DefaultMessageIDTypes中都是内部消息id,需要添加自定义消息id,则使用如下方法:

 enum {
   ID_MYPROJECT_MSG_1 = ID_USER_PACKET_ENUM,
   ID_MYPROJECT_MSG_2, 
    ... 
 };

8、比特流 BitStream

用一个封装的动态数组来打包和解包bits,具有四个优势:1. 动态创建数据报;2. 数据压缩;3. 写入Bits;4. 数据字节序转换。

Bitstream是作为模板类,可以容纳任何类型数据。如果这是一个内置的类型(NetwordIDObject),它使用部分模板实现使得类型写入更加有效。如果是局部类型或一个结构体,它可以写入单独的内存数据(比特流、序列化对象)。

struct MyVector  //写数据
{
         float x,y,z;
} myVector;

bitStream.Write(myVector);// 没有字节序交换

#undef __BITSTREAM_NATIVE_END  // 带有字节序交换
bitStream.Write(myVector.x);
bitStream.Write(myVector.y);
bitStream.Write(myVector.z);

// 也可以重写操作符
namespace RakNet
{
       RakNet::BitStream& operator << (RakNet::BitStream& out, MyVector& in)
       {
              out.WriteNormVector(in.x,in.y,in.z);
              return out;
       }

       RakNet::BitStream& operator >> (RakNet::BitStream& in, MyVector& out)
       {
             bool success = in.ReadNormVector(out.x,out.y,out.z);
              assert(success);
              return in;
       }
} 

myVector << bitStream;// 从bitstream读取数据
myVector >> bitStream;// 向bitstream写入数据
可选—其中的一个构造函数是以长度作为参数。如果大概知道数据的大小,在构造Bitstream对象的时候可以将这个参数传递给Bitstream的构造函数,可以避免在生成bitstream对象后在动态重新分配内存。

读取数据也是一样的简单。创建一个bitstream,在构造函数中赋值给它数据。

// 假设我们接收到一个数据包Packet *
BitStream myBitStream(packet->data, packet->length, false);
struct MyVector
{
       float x,y,z;
} myVector;

// 没有字节序转换
bitStream.Read(myVector);

// 要转换字节序(__BITSTREAM_NATIVE_END在RakNetDefines.h中要注释掉)
#undef __BITSTREAM_NATIVE_END
#include "BitStream.h"

bitStream.Read(myVector.x);
bitStream.Read(myVector.y);
bitStream.Read(myVector.z);
序列化数据:需要同时使用相同的函数Read和Write,可以使用BitStream::Serialize()代替Read()和Write()
struct MyVector
{
       float x,y,z;
       // 如果ToBitstream==true,则是写入数据, 如果ToBitstream==false,则是读取数据
       void Serialize(bool writeToBitstream, BitStream *bs)
       {
              bs->Serialize(writeToBitstream, x);
              bs->Serialize(writeToBitstream, y);
              bs->Serialize(writeToBitstream, z);
       }
} myVector;

测试如下:

	struct EmploymentStruct //自定义结构体
	{
		int salary;
		unsigned char yearsEmployed;
	};

	void clientRPC(RPCParameters *rpcParameters) //远程调用rpc
	{
		BitStream b(rpcParameters->input, BITS_TO_BYTES(rpcParameters->numberOfBitsOfData), false); //构建比特流
		char name[200]; //名称

		//      printf("GOT RPC:\n");
		//      b.PrintBits();
		unsigned char nameLength;
		b.Read(nameLength);
		if (b.Read(name, nameLength)==false) // 获取名称
		{
			printf("Name was not null-terminated!\n");
			return;
		}
		name[nameLength]=0; // Name is now null terminated
		printf("In clientRPC:\n");
		printf("Name is %s\n", name);

		unsigned int age;
		if (b.ReadCompressed(age)==false)
			return;

		printf("Age is %i\n", age);
		fflush(stdout);

		bool wroteEmploymentStruct;
		if (b.Read(wroteEmploymentStruct)==false)
		{
			return;
		}

		if (wroteEmploymentStruct)
		{
			printf("We are employed.\n");
			EmploymentStruct employmentStruct;
			if (b.Read(employmentStruct.salary)==false) return;
			if (b.Read(employmentStruct.yearsEmployed)==false) return;

			printf("Salary is %i.  Years employed is %i\n", employmentStruct.salary, (int)employmentStruct.yearsEmployed);
		}
		else
			printf("We are between jobs :)\n");

		quit=true;
	}

#if defined(_PS3) || defined(__PS3__)

#endif

	int main(void)
	{
		RakPeerInterface *rakClient=RakNetworkFactory::GetRakPeerInterface();
		RakPeerInterface *rakServer=RakNetworkFactory::GetRakPeerInterface();
#ifndef WIN32
#define getch getchar
#endif


#if defined(_PS3) || defined(__PS3__)
#endif
		quit=false;
		char text[255];

		// Defined in RakNetTypes.h.
		// You can register a function anytime
		REGISTER_STATIC_RPC(rakClient, clientRPC);

		//rakServer->InitializeSecurity(0,0,0,0);

		SocketDescriptor socketDescriptor(10000,0);
		if (rakServer->Startup(1,30,&socketDescriptor, 1)==false)
		{
			printf("Start call failed!\n");

			fflush(stdout);
			fgets(text, sizeof(text), stdin);
			printf("\n");
			return 0;
		}
		rakServer->SetMaximumIncomingConnections(1);
		socketDescriptor.port=0;
		rakClient->Startup(1, 30, &socketDescriptor, 1);
		if (rakClient->Connect("127.0.0.1", 10000, 0, 0)==false)
		{
			printf("Connect call failed\n");
			fflush(stdout);
			fgets(text, sizeof(text), stdin);
			printf("\n");
			return 0;
		}

		BitStream outgoingBitstream;
		unsigned int age;
		printf("A sample on how to use RakNet‘s bitstream class\n");
		printf("Difficulty: Beginner\n\n");

		printf("Enter your name.\n");
		fflush(stdout);
		fgets(text, sizeof(text), stdin);
		printf("\n");
		if (text[0]==0)
			strcpy(text, "Unnamed!");
		outgoingBitstream.Write((unsigned char)strlen(text));
		outgoingBitstream.Write(text, (int) strlen(text));

		printf("Enter your age (numbers only).\n");
		fflush(stdout);
		fgets(text, sizeof(text), stdin);
		printf("\n");
		if (text[0]==0)
			age=0;
		else
			age=atoi(text);
		outgoingBitstream.WriteCompressed(age);
		printf("Are you employed (y/n)?\n");
		fflush(stdout);
		fgets(text, sizeof(text), stdin);
		printf("\n");
		if (text[0]==‘y‘)
		{
			outgoingBitstream.Write(true); // Writing a bool takes 1 bit

			// Read some data into a struct
			EmploymentStruct employmentStruct;
			printf("What is your salary (enter a number only)?\n");
			fflush(stdout);
			fgets(text, sizeof(text), stdin);
			printf("\n");
			employmentStruct.salary = atoi(text);
			printf("How many years have you been employed (enter a number only)?\n");
			fflush(stdout);
			fgets(text, sizeof(text), stdin);
			printf("\n");
			employmentStruct.yearsEmployed = atoi(text);

			// We can write structs to a bitstream but this is not portable due to:
			//  1. Different-endian CPUs
			//  2. Different ‘padding‘ of structs depending on compiler, etc
			// The only safe way to send a struct is by using the BitStream
			// to write out every single member which you want to send.
			outgoingBitstream.Write(employmentStruct.salary);
			outgoingBitstream.Write(employmentStruct.yearsEmployed);
			// We‘re done writing to the struct
		}
		else
		{
			//printf("Number of bits before [false]: %d\n",
			//outgoingBitstream.GetNumberOfBitsUsed() );
			outgoingBitstream.Write(false); // Writing a bool takes 1 bit
			// We‘re done writing to the struct.  Compare this to the example above - we wrote quite a bit less.
		}

		printf("Waiting for connection...\n");
		while (rakClient->GetSystemAddressFromIndex(0)==UNASSIGNED_SYSTEM_ADDRESS)
			RakSleep(30);
		printf("Connected.\n");

		//      printf("SEND RPC:\n");
		//      outgoingBitstream.PrintBits();

		// RPC functions as well as send can take bitstreams directly
		bool success = rakServer->RPC("clientRPC",&outgoingBitstream, HIGH_PRIORITY, RELIABLE, 0, UNASSIGNED_SYSTEM_ADDRESS, true, 0, UNASSIGNED_NETWORK_ID, 0); // broadcast to everyone, which happens to be our one client
		if (!success)
			printf("RPC call failed\n");

		while (!quit)
		{
			rakClient->DeallocatePacket(rakClient->Receive());
			rakServer->DeallocatePacket(rakServer->Receive());

			RakSleep(30);
		}
		printf("Press enter to quit\n");
		fflush(stdout);
		264	        fgets(text, sizeof(text), stdin);
		printf("\n");

		rakClient->Shutdown(100,0);
		rakServer->Shutdown(100,0);

		// This is not necessary since on shutdown everything is unregistered.  This is just here to show usage
		UNREGISTER_STATIC_RPC(rakClient, clientRPC);

		RakNetworkFactory::DestroyRakPeerInterface(rakClient);
		RakNetworkFactory::DestroyRakPeerInterface(rakServer);

		return 0;
	}

9、内部网络数据包

结构:

struct Packet
{
	/// The system that send this packet.
	SystemAddress systemAddress; //地址信息

	/// A unique identifier for the system that sent this packet, regardless of IP address (internal / external / remote system)
	/// Only valid once a connection has been established (ID_CONNECTION_REQUEST_ACCEPTED, or ID_NEW_INCOMING_CONNECTION)
	/// Until that time, will be UNASSIGNED_RAKNET_GUID
	RakNetGUID guid;

	/// The length of the data in bytes
	unsigned int length;

	/// The length of the data in bits
	BitSize_t bitSize;

	/// The data from the sender
	unsigned char* data;

	/// @internal
	/// Indicates whether to delete the data, or to simply delete the packet.
	bool deleteData;

	/// @internal
	/// If true, this message is meant for the user, not for the plugins, so do not process it through plugins
	bool wasGeneratedLocally;
};

源码如下:

typedef uint16_t SplitPacketIdType; //id标识类型
typedef uint32_t SplitPacketIndexType; //序列类型

/// This is the counter used for holding packet numbers, so we can detect duplicate packets.  It should be large enough that if the variables
/// Internally assumed to be 4 bytes, but written as 3 bytes in ReliabilityLayer::WriteToBitStreamFromInternalPacket
typedef uint24_t MessageNumberType; //保持分组数的计数器,可以检测到重复的数据包。

/// This is the counter used for holding ordered packet numbers, so we can detect out-of-order packets.  It should be large enough that if the variables
/// were to wrap, the newly wrapped values would no longer be in use.  Warning: Too large of a value wastes bandwidth!
typedef MessageNumberType OrderingIndexType;//用来保持有序的包数的计数器,可以检测出数据包的顺序。

typedef RakNet::TimeUS RemoteSystemTimeType;

struct InternalPacketFixedSizeTransmissionHeader
{
	/// A unique numerical identifier given to this user message. Used to identify reliable messages on the network
	MessageNumberType reliableMessageNumber; //唯一标识 号码

	///The ID used as identification for ordering messages. Also included in sequenced messages
	OrderingIndexType orderingIndex; //排序消息识别

	// Used only with sequenced messages
	OrderingIndexType sequencingIndex;//用于排序消息

	///What ordering channel this packet is on, if the reliability type uses ordering channels
	unsigned char orderingChannel; //顺序通道

	///The ID of the split packet, if we have split packets.  This is the maximum number of split messages we can send simultaneously per connection.
	SplitPacketIdType splitPacketId; //分包标识

	///If this is a split packet, the index into the array of subsplit packets
	SplitPacketIndexType splitPacketIndex;//分包序列

	///The size of the array of subsplit packets
	SplitPacketIndexType splitPacketCount; //分包总数

	///How many bits long the data is
	BitSize_t dataBitLength; //数据长度

	///What type of reliability algorithm to use with this packet
	PacketReliability reliability;//可靠性算法
	// Not endian safe
	// unsigned char priority : 3;
	// unsigned char reliability : 5;
};

/// Used in InternalPacket when pointing to sharedDataBlock, rather than allocating itself
struct InternalPacketRefCountedData //引用计数
{
	unsigned char *sharedDataBlock;
	unsigned int refCount;
};

/// Holds a user message, and related information
/// Don‘t use a constructor or destructor, due to the memory pool I am using
struct InternalPacket : public InternalPacketFixedSizeTransmissionHeader //内部数据包
{
	/// Identifies the order in which this number was sent. Used locally
	MessageNumberType messageInternalOrder; //唯一标识

	/// Has this message number been assigned yet?  We don‘t assign until the message is actually sent.
	/// This fixes a bug where pre-determining message numbers and then sending a message on a different channel creates a huge gap.
	/// This causes performance problems and causes those messages to timeout.
	bool messageNumberAssigned; //是否被分配标识

	/// Was this packet number used this update to track windowing drops or increases?  Each packet number is only used once per update.
//	bool allowWindowUpdate;
	///When this packet was created
	RakNet::TimeUS creationTime; //创建时间

	///The resendNext time to take action on this packet
	RakNet::TimeUS nextActionTime; //下个动作时间

	// For debugging
	RakNet::TimeUS retransmissionTime; //丢失时间

	// Size of the header when encoded into a bitstream
	BitSize_t headerLength; //头长度信息

	/// Buffer is a pointer to the actual data, assuming this packet has data at all
	unsigned char *data; //数据内容

	/// How to alloc and delete the data member
	enum AllocationScheme //定义申请内容方式
	{
		/// Data is allocated using rakMalloc. Just free it
		NORMAL, //正常情况

		/// data points to a larger block of data, where the larger block is reference counted. internalPacketRefCountedData is used in this case
		REF_COUNTED, //引用计数
	
		/// If allocation scheme is STACK, data points to stackData and should not be deallocated
		/// This is only used when sending. Received packets are deallocated in RakPeer
		STACK //栈模式
	} allocationScheme;
	InternalPacketRefCountedData *refCountedData; //引用计数

	/// How many attempts we made at sending this message
	unsigned char timesSent; //发送时间

	/// The priority level of this packet
	PacketPriority priority; //优先级

	/// If the reliability type requires a receipt, then return this number with it
	uint32_t sendReceiptSerial; //可靠性统计

	// Used for the resend queue
	// Linked list implementation so I can remove from the list via a pointer, without finding it in the list
	InternalPacket *resendPrev, *resendNext,*unreliablePrev,*unreliableNext; //发送队列

	unsigned char stackData[128]; //堆栈数据
};

6、网络id标识

定义如下:

typedef uint64_t NetworkID;
struct RAK_DLL_EXPORT RakNetGUID
{
	RakNetGUID();
	explicit RakNetGUID(uint64_t _g) {g=_g; systemIndex=(SystemIndex)-1;}
//	uint32_t g[6];
	uint64_t g;

	// Return the GUID as a string
	// Returns a static string
	// NOT THREADSAFE
	const char *ToString(void) const;

	// Return the GUID as a string
	// dest must be large enough to hold the output
	// THREADSAFE
	void ToString(char *dest) const;

	bool FromString(const char *source);

	static unsigned long ToUint32( const RakNetGUID &g );

	RakNetGUID& operator = ( const RakNetGUID& input )
	{
		g=input.g;
		systemIndex=input.systemIndex;
		return *this;
	}

	// Used internally for fast lookup. Optional (use -1 to do regular lookup). Don‘t transmit this.
	SystemIndex systemIndex;
	static int size() {return (int) sizeof(uint64_t);}

	bool operator==( const RakNetGUID& right ) const;
	bool operator!=( const RakNetGUID& right ) const;
	bool operator > ( const RakNetGUID& right ) const;
	bool operator < ( const RakNetGUID& right ) const;
};
class RAK_DLL_EXPORT NetworkIDObject
{
public:
	// Constructor.  NetworkIDs, if IsNetworkIDAuthority() is true, are created here.
	NetworkIDObject();

	// Destructor.  Used NetworkIDs, if any, are freed here.
	virtual ~NetworkIDObject();

	/// Sets the manager class from which to request unique network IDs
	/// Unlike previous versions, the NetworkIDObject relies on a manager class to provide IDs, rather than using statics,
	/// So you can have more than one set of IDs on the same system.
	virtual void SetNetworkIDManager( NetworkIDManager *manager); //附属哪个管理

	/// Returns what was passed to SetNetworkIDManager
	virtual NetworkIDManager * GetNetworkIDManager( void ) const; //返回管理
	
	/// Returns the NetworkID that you can use to refer to this object over the network.
	/// \pre You must first call SetNetworkIDManager before using this function
	/// \retval UNASSIGNED_NETWORK_ID UNASSIGNED_NETWORK_ID is returned IsNetworkIDAuthority() is false and SetNetworkID() was not previously called.  This is also returned if you call this function in the constructor.
	/// \retval 0-65534 Any other value is a valid NetworkID.  NetworkIDs start at 0 and go to 65534, wrapping at that point.
	virtual NetworkID GetNetworkID( void ); //获取id
	
	/// Sets the NetworkID for this instance.  Usually this is called by the clients and determined from the servers.  However, if you save multiplayer games you would likely use
	/// This on load as well.	
	virtual void SetNetworkID( NetworkID id ); //设置id

	/// Your class does not have to derive from NetworkIDObject, although that is the easiest way to implement this.
	/// If you want this to be a member object of another class, rather than inherit, then call SetParent() with a pointer to the parent class instance.
	/// GET_OBJECT_FROM_ID will then return the parent rather than this instance.
	virtual void SetParent( void *_parent ); //设置父类

	/// Return what was passed to SetParent
	/// \return The value passed to SetParent, or 0 if it was never called.
	virtual void* GetParent( void ) const; //获取父类
	
protected:

	/// The  network ID of this object
	// networkID is assigned when networkIDManager is set.
	NetworkID networkID;	
	NetworkIDManager *networkIDManager;

	/// The parent set by SetParent()
	void *parent;

	/// \internal, used by NetworkIDManager
	friend class NetworkIDManager;
	NetworkIDObject *nextInstanceForNetworkIDManager;
};

10、接口

enum PluginReceiveResult //返回结果
{
	/// The plugin used this message and it shouldn‘t be given to the user.
	RR_STOP_PROCESSING_AND_DEALLOCATE=0,

	/// This message will be processed by other plugins, and at last by the user.
	RR_CONTINUE_PROCESSING,

	/// The plugin is going to hold on to this message.  Do not deallocate it but do not pass it to other plugins either.
	RR_STOP_PROCESSING
};
enum PI2_LostConnectionReason //丢失原因
{
	/// Called RakPeer::CloseConnection()
	LCR_CLOSED_BY_USER,

	/// Got ID_DISCONNECTION_NOTIFICATION
	LCR_DISCONNECTION_NOTIFICATION,

	/// GOT ID_CONNECTION_LOST
	LCR_CONNECTION_LOST
};
enum PI2_FailedConnectionAttemptReason //失败原因
{
	FCAR_CONNECTION_ATTEMPT_FAILED,
	FCAR_ALREADY_CONNECTED,
	FCAR_NO_FREE_INCOMING_CONNECTIONS,
	FCAR_SECURITY_PUBLIC_KEY_MISMATCH,
	FCAR_CONNECTION_BANNED,
	FCAR_INVALID_PASSWORD,
	FCAR_INCOMPATIBLE_PROTOCOL,
	FCAR_IP_RECENTLY_CONNECTED,
	FCAR_REMOTE_SYSTEM_REQUIRES_PUBLIC_KEY,
	FCAR_OUR_SYSTEM_REQUIRES_SECURITY,
	FCAR_PUBLIC_KEY_MISMATCH
};
接口类:

class RAK_DLL_EXPORT PluginInterface2  //插件类
{
public:
	PluginInterface2();
	virtual ~PluginInterface2();

	/// Called when the interface is attached
	virtual void OnAttach(void) {} //绑定

	/// Called when the interface is detached
	virtual void OnDetach(void) {} //断开

	/// Update is called every time a packet is checked for .
	virtual void Update(void) {} //更新

	/// OnReceive is called for every packet.
	/// \param[in] packet the packet that is being returned to the user
	/// \return True to allow the game and other plugins to get this message, false to absorb it
	virtual PluginReceiveResult OnReceive(Packet *packet) {(void) packet; return RR_CONTINUE_PROCESSING;} //接收到数据,进行处理

	/// Called when RakPeer is initialized
	virtual void OnRakPeerStartup(void) {} //启动

	/// Called when RakPeer is shutdown
	virtual void OnRakPeerShutdown(void) {}//关闭

	/// Called when a connection is dropped because the user called RakPeer::CloseConnection() for a particular system
	/// \param[in] systemAddress The system whose connection was closed
	/// \param[in] rakNetGuid The guid of the specified system
	/// \param[in] lostConnectionReason How the connection was closed: manually, connection lost, or notification of disconnection
	virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason ){(void) systemAddress; (void) rakNetGUID; (void) lostConnectionReason;} 

	/// Called when we got a new connection
	/// \param[in] systemAddress Address of the new connection
	/// \param[in] rakNetGuid The guid of the specified system
	/// \param[in] isIncoming If true, this is ID_NEW_INCOMING_CONNECTION, or the equivalent
	virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming) {(void) systemAddress; (void) rakNetGUID; (void) isIncoming;}

	/// Called when a connection attempt fails
	/// \param[in] packet Packet to be returned to the user
	/// \param[in] failedConnectionReason Why the connection failed
	virtual void OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason) {(void) packet; (void) failedConnectionAttemptReason;}

	/// Queried when attached to RakPeer
	/// Return true to call OnDirectSocketSend(), OnDirectSocketReceive(), OnReliabilityLayerNotification(), OnInternalPacket(), and OnAck()
	/// If true, then you cannot call RakPeer::AttachPlugin() or RakPeer::DetachPlugin() for this plugin, while RakPeer is active
	virtual bool UsesReliabilityLayer(void) const {return false;}

	/// Called on a send to the socket, per datagram, that does not go through the reliability layer
	/// \pre To be called, UsesReliabilityLayer() must return true
	/// \param[in] data The data being sent
	/// \param[in] bitsUsed How many bits long \a data is
	/// \param[in] remoteSystemAddress Which system this message is being sent to
	virtual void OnDirectSocketSend(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress) {(void) data; (void) bitsUsed; (void) remoteSystemAddress;}
	
	/// Called on a receive from the socket, per datagram, that does not go through the reliability layer
	/// \pre To be called, UsesReliabilityLayer() must return true
	/// \param[in] data The data being sent
	/// \param[in] bitsUsed How many bits long \a data is
	/// \param[in] remoteSystemAddress Which system this message is being sent to
	virtual void OnDirectSocketReceive(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress) {(void) data; (void) bitsUsed; (void) remoteSystemAddress;}

	/// Called when the reliability layer rejects a send or receive
	/// \pre To be called, UsesReliabilityLayer() must return true
	/// \param[in] bitsUsed How many bits long \a data is
	/// \param[in] remoteSystemAddress Which system this message is being sent to
	virtual void OnReliabilityLayerNotification(const char *errorMessage, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress, bool isError)  {(void) errorMessage; (void) bitsUsed; (void) remoteSystemAddress; (void) isError;}
	
	/// Called on a send or receive of a message within the reliability layer
	/// \pre To be called, UsesReliabilityLayer() must return true
	/// \param[in] internalPacket The user message, along with all send data.
	/// \param[in] frameNumber The number of frames sent or received so far for this player depending on \a isSend .  Indicates the frame of this user message.
	/// \param[in] remoteSystemAddress The player we sent or got this packet from
	/// \param[in] time The current time as returned by RakNet::GetTimeMS()
	/// \param[in] isSend Is this callback representing a send event or receive event?
	virtual void OnInternalPacket(InternalPacket *internalPacket, unsigned frameNumber, SystemAddress remoteSystemAddress, RakNet::TimeMS time, int isSend) {(void) internalPacket; (void) frameNumber; (void) remoteSystemAddress; (void) time; (void) isSend;}

	/// Called when we get an ack for a message we reliably sent
	/// \pre To be called, UsesReliabilityLayer() must return true
	/// \param[in] messageNumber The numerical identifier for which message this is
	/// \param[in] remoteSystemAddress The player we sent or got this packet from
	/// \param[in] time The current time as returned by RakNet::GetTimeMS()
	virtual void OnAck(unsigned int messageNumber, SystemAddress remoteSystemAddress, RakNet::TimeMS time) {(void) messageNumber; (void) remoteSystemAddress; (void) time;}

	/// System called RakPeerInterface::PushBackPacket
	/// \param[in] data The data being sent
	/// \param[in] bitsUsed How many bits long \a data is
	/// \param[in] remoteSystemAddress The player we sent or got this packet from
	virtual void OnPushBackPacket(const char *data, const BitSize_t bitsUsed, SystemAddress remoteSystemAddress) {(void) data; (void) bitsUsed; (void) remoteSystemAddress;}

	RakPeerInterface *GetRakPeerInterface(void) const {return rakPeerInterface;}

	RakNetGUID GetMyGUIDUnified(void) const;

	/// \internal
	void SetRakPeerInterface( RakPeerInterface *ptr );

#if _RAKNET_SUPPORT_TCPInterface==1
	/// \internal
	void SetTCPInterface( TCPInterface *ptr );
#endif

protected:
	// Send through either rakPeerInterface or tcpInterface, whichever is available
	void SendUnified( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );
	void SendUnified( const char * data, const int length, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );
	bool SendListUnified( const char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast );

	Packet *AllocatePacketUnified(unsigned dataSize);
	void PushBackPacketUnified(Packet *packet, bool pushAtHead);
	void DeallocPacketUnified(Packet *packet);

	// Filled automatically in when attached
	RakPeerInterface *rakPeerInterface;
#if _RAKNET_SUPPORT_TCPInterface==1
	TCPInterface *tcpInterface;
#endif
};

11、邮箱发送

直接应用EmailSender,便可实现邮箱发送,类定义如下:

class RAK_DLL_EXPORT EmailSender
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(EmailSender)

	/// \brief Sends an email.
	/// \param[in] hostAddress The address of the email server.
	/// \param[in] hostPort The port of the email server (usually 25)
	/// \param[in] sender The email address you are sending from.
	/// \param[in] recipient The email address you are sending to.
	/// \param[in] senderName The email address you claim to be sending from
	/// \param[in] recipientName The email address you claim to be sending to
	/// \param[in] subject Email subject
	/// \param[in] body Email body
	/// \param[in] attachedFiles List of files to attach to the email. (Can be 0 to send none).
	/// \param[in] doPrintf true to output SMTP info to console(for debugging?)
	/// \param[in] password Used if the server uses AUTHENTICATE PLAIN over TLS (such as gmail)
	/// \return 0 on success, otherwise a string indicating the error message
	const char *Send(const char *hostAddress, unsigned short hostPort, const char *sender, const char *recipient, const char *senderName, const char *recipientName, const char *subject, const char *body, FileList *attachedFiles, bool doPrintf, const char *password);

protected:
	const char *GetResponse(TCPInterface *tcpInterface, const SystemAddress &emailServer, bool doPrintf);
	RakNetRandom rakNetRandom;
};

测试如下:

int main()
{
	printf("A C++ class used to send email, such as for servers.\n");
	printf("TLS support (such as for Gmail) requires OPEN_SSL_CLIENT_SUPPORT to be defined\nin RakNetDefines.h.\n");
	printf("Difficulty: Beginner\n\n");

	RakNet::FileList fileList;
	RakNet::EmailSender emailSender;
	const char *quote = "Man is distinguished, not only by his reason, but by this singular passion from other animals, which is a lust of the mind, that by a perseverance of delight in the continued and indefatigable generation of knowledge, exceeds the short vehemence of any carnal pleasure.";
//	const char base64Map[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
//	char output[1024];
//	emailSender.Base64Encoding(quote, strlen(quote), output, base64Map);
//	printf("%s", output);

	char mailServer[128], senderUsername[128], receiver[128], password[128];
	printf("Tests sending email.\n");
	printf("Enter mail server: ");
	Gets(mailServer,sizeof(mailServer));
	if (mailServer[0]==0)
		strcpy(mailServer, "smtp.gmail.com");
	printf("Enter email account username: ");
	Gets(senderUsername,sizeof(senderUsername));
	if (senderUsername[0]==0)
		strcpy(senderUsername, "subspacegod@gmail.com");
	printf("Enter receiver email address: ");
	Gets(receiver,sizeof(receiver));
	if (receiver[0]==0)
		strcpy(receiver, "rakkar@rakkar.org");
	printf("Enter password needed to send: ");
	Gets(password,sizeof(password));


	// http://mail.google.com/support/bin/answer.py?hl=en&answer=13287
	unsigned short hostPort;
	if (strcmp(mailServer,"smtp.gmail.com")==0)
		hostPort=465;
	else
		hostPort=25;

	fileList.AddFile("quote.txt", "quote.txt", quote, (const unsigned int) strlen(quote), (const unsigned int) strlen(quote), FileListNodeContext(0,0,0,0), false);
	const char *sendResult=emailSender.Send(mailServer,
		hostPort,
		senderUsername,
		receiver,
		senderUsername,
		receiver,
		"Test subject.",
		"Test attachment body :).\n.\n..\n.\n(Should be .,.,..,.)\r\n.\r\n.\r\n..\r\n.\r\n(Should be .,.,..,.)12345\r\n.\r\n",
		&fileList,
		true,
		password);
	if (sendResult!=0)
		printf("Send Failed! %s", sendResult);
	else
		printf("Success (probably).\n");
	printf("Press enter to quit.\n");
	char buff[256];
	Gets(buff,sizeof(buff));

	return 0;
}

12、日志

流程操作的一种记录。

主要实现类:

class RAK_DLL_EXPORT LogCommandParser : public CommandParserInterface

13、消息过滤插件

结构如下:

struct FilterSet
{
	bool banOnFilterTimeExceed;
	bool kickOnDisallowedMessage;
	bool banOnDisallowedMessage;
	RakNet::TimeMS disallowedMessageBanTimeMS;
	RakNet::TimeMS timeExceedBanTimeMS;
	RakNet::TimeMS maxMemberTimeMS;
	void (*invalidMessageCallback)(RakPeerInterface *peer, AddressOrGUID systemAddress, int filterSetID, void *userData, unsigned char messageID);
	void *disallowedCallbackUserData;
	void (*timeoutCallback)(RakPeerInterface *peer, AddressOrGUID systemAddress, int filterSetID, void *userData);
	void *timeoutUserData;
	int filterSetID;
	bool allowedIDs[MESSAGE_FILTER_MAX_MESSAGE_ID];
	DataStructures::OrderedList<RakNet::RakString,RakNet::RakString> allowedRPC4;
};
struct FilteredSystem
{
	FilterSet *filter;
	RakNet::TimeMS timeEnteredThisSet;
};
主要实现类:

class RAK_DLL_EXPORT MessageFilter : public PluginInterface2
关键成员:

DataStructures::OrderedList<int, FilterSet*, FilterSetComp> filterList;
	// Change to guid
	DataStructures::Hash<AddressOrGUID, FilteredSystem, 2048, AddressOrGUID::ToInteger> systemList;

14、双向认证

单项认证:就是比如你有个密码 用户名 然后和服务器上的用户信息进行比对 一致的话你们就可以建立连接.
双向认证就是:你有个密码 用户名 你先发给服务器进行比对,如果一致服务器再把它的密码用户名发到你机器上与你机器上保留的用户信息进行比对 如果还一致则建立链接!

实现类:

class RAK_DLL_EXPORT TwoWayAuthentication : public PluginInterface2
内部结构:

/// \internal
	struct PendingChallenge
	{
		RakNet::RakString identifier;
		AddressOrGUID remoteSystem;
		RakNet::Time time;
		bool sentHash;
	};

	DataStructures::Queue<PendingChallenge> outgoingChallenges;

	/// \internal
	struct NonceAndRemoteSystemRequest
	{
		char nonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH];
		RakNet::AddressOrGUID remoteSystem;
		unsigned short requestId;
		RakNet::Time whenGenerated;
	};
	/// \internal
	struct RAK_DLL_EXPORT NonceGenerator
	{
		NonceGenerator();
		~NonceGenerator();
		void GetNonce(char nonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH], unsigned short *requestId, RakNet::AddressOrGUID remoteSystem);
		void GenerateNonce(char nonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH]);
		bool GetNonceById(char nonce[TWO_WAY_AUTHENTICATION_NONCE_LENGTH], unsigned short requestId, RakNet::AddressOrGUID remoteSystem, bool popIfFound);
		void Clear(void);
		void ClearByAddress(RakNet::AddressOrGUID remoteSystem);
		void Update(RakNet::Time curTime);

		DataStructures::List<TwoWayAuthentication::NonceAndRemoteSystemRequest*> generatedNonces;
		unsigned short nextRequestId;
	};
关键成员:

	// Key is identifier, data is password
	DataStructures::Hash<RakNet::RakString, RakNet::RakString, 16, RakNet::RakString::ToInteger > passwords;

15、传输接口

class RAK_DLL_EXPORT TransportInterface //用于发送和接收的数据
{
public:
	TransportInterface() {}
	virtual ~TransportInterface() {}

	/// Start the transport provider on the indicated port.
	/// \param[in] port The port to start the transport provider on
	/// \param[in] serverMode If true, you should allow incoming connections (I don‘t actually use this anywhere)
	/// \return Return true on success, false on failure.
	virtual bool Start(unsigned short port, bool serverMode)=0;

	/// Stop the transport provider.  You can clear memory and shutdown threads here.
	virtual void Stop(void)=0;

	/// Send a null-terminated string to \a systemAddress
	/// If your transport method requires particular formatting of the outgoing data (e.g. you don‘t just send strings) you can do it here
	/// and parse it out in Receive().
	/// \param[in] systemAddress The player to send the string to
	/// \param[in] data format specifier - same as RAKNET_DEBUG_PRINTF
	/// \param[in] ... format specification arguments - same as RAKNET_DEBUG_PRINTF
	virtual void Send( SystemAddress systemAddress, const char *data, ... )=0;

	/// Disconnect \a systemAddress .  The binary address and port defines the SystemAddress structure.
	/// \param[in] systemAddress The player/address to disconnect
	virtual void CloseConnection( SystemAddress systemAddress )=0;

	/// Return a string. The string should be allocated and written to Packet::data .
	/// The byte length should be written to Packet::length .  The player/address should be written to Packet::systemAddress
	/// If your transport protocol adds special formatting to the data stream you should parse it out before returning it in the packet
	/// and thus only return a string in Packet::data
	/// \return The packet structure containing the result of Receive, or 0 if no data is available
	virtual Packet* Receive( void )=0;

	/// Deallocate the Packet structure returned by Receive
	/// \param[in] The packet to deallocate
	virtual void DeallocatePacket( Packet *packet )=0;

	/// If a new system connects to you, you should queue that event and return the systemAddress/address of that player in this function.
	/// \return The SystemAddress/address of the system
	virtual SystemAddress HasNewIncomingConnection(void)=0;

	/// If a system loses the connection, you should queue that event and return the systemAddress/address of that player in this function.
	/// \return The SystemAddress/address of the system
	virtual SystemAddress HasLostConnection(void)=0;

	/// Your transport provider can itself have command parsers if the transport layer has user-modifiable features
	/// For example, your transport layer may have a password which you want remote users to be able to set or you may want
	/// to allow remote users to turn on or off command echo
	/// \return 0 if you do not need a command parser - otherwise the desired derivation of CommandParserInterface
	virtual CommandParserInterface* GetCommandParser(void)=0;
protected:
};

16、网络类型匹配

网络类型匹配分客户端和服务端,如下:

	/// All possible types of NATs (except NAT_TYPE_COUNT, which is an internal value) 
	enum NATTypeDetectionResult //匹配结果
	{
		/// Works with anyone
		NAT_TYPE_NONE,
		/// Accepts any datagrams to a port that has been previously used. Will accept the first datagram from the remote peer.
		NAT_TYPE_FULL_CONE,
		/// Accepts datagrams to a port as long as the datagram source IP address is a system we have already sent to. Will accept the first datagram if both systems send simultaneously. Otherwise, will accept the first datagram after we have sent one datagram.
		NAT_TYPE_ADDRESS_RESTRICTED,
		/// Same as address-restricted cone NAT, but we had to send to both the correct remote IP address and correct remote port. The same source address and port to a different destination uses the same mapping.
		NAT_TYPE_PORT_RESTRICTED,
		/// A different port is chosen for every remote destination. The same source address and port to a different destination uses a different mapping. Since the port will be different, the first external punchthrough attempt will fail. For this to work it requires port-prediction (MAX_PREDICTIVE_PORT_RANGE>1) and that the router chooses ports sequentially.
		NAT_TYPE_SYMMETRIC,
		/// Hasn‘t been determined. NATTypeDetectionClient does not use this, but other plugins might
		NAT_TYPE_UNKNOWN,
		/// In progress. NATTypeDetectionClient does not use this, but other plugins might
		NAT_TYPE_DETECTION_IN_PROGRESS,
		/// Didn‘t bother figuring it out, as we support UPNP, so it is equivalent to NAT_TYPE_NONE. NATTypeDetectionClient does not use this, but other plugins might
		NAT_TYPE_SUPPORTS_UPNP,
		/// \internal Must be last
		NAT_TYPE_COUNT
	};
	class RAK_DLL_EXPORT NatTypeDetectionClient : public PluginInterface2, public RNS2EventHandler
	{ //客户端
	public:

		// GetInstance() and DestroyInstance(instance*)
		STATIC_FACTORY_DECLARATIONS(NatTypeDetectionClient)

		// Constructor
		NatTypeDetectionClient();

		// Destructor
		virtual ~NatTypeDetectionClient();

		/// Send the message to the server to detect the nat type
		/// Server must be running NatTypeDetectionServer
		/// We must already be connected to the server
		/// \param[in] serverAddress address of the server
		void DetectNATType(SystemAddress _serverAddress);

		/// \internal For plugin handling
		virtual void Update(void);

		/// \internal For plugin handling
		virtual PluginReceiveResult OnReceive(Packet *packet);

		virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
		virtual void OnRakPeerShutdown(void);
		virtual void OnDetach(void);

		virtual void OnRNS2Recv(RNS2RecvStruct *recvStruct);
		virtual void DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line);
		virtual RNS2RecvStruct *AllocRNS2RecvStruct(const char *file, unsigned int line);
	protected:
		DataStructures::Queue<RNS2RecvStruct*> bufferedPackets;
		SimpleMutex bufferedPacketsMutex;
		
		RakNetSocket2* c2;
		//unsigned short c2Port;
		void Shutdown(void);
		void OnCompletion(NATTypeDetectionResult result);
		bool IsInProgress(void) const;

		void OnTestPortRestricted(Packet *packet);
		SystemAddress serverAddress;
	};
class RAK_DLL_EXPORT NatTypeDetectionServer : public PluginInterface2, public RNS2EventHandler
{ //服务端
public:

	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(NatTypeDetectionServer)

	// Constructor
	NatTypeDetectionServer();

	// Destructor
	virtual ~NatTypeDetectionServer();

	/// Start the system, binding to 3 external IPs not already in useS
	/// \param[in] nonRakNetIP2 First unused external IP
	/// \param[in] nonRakNetIP3 Second unused external IP
	/// \param[in] nonRakNetIP4 Third unused external IP
	void Startup(
		const char *nonRakNetIP2,
		const char *nonRakNetIP3,
		const char *nonRakNetIP4
#ifdef __native_client__
		,_PP_Instance_ chromeInstance
#endif
		);

	// Releases the sockets created in Startup();
	void Shutdown(void);

	/// \internal For plugin handling
	virtual void Update(void);

	/// \internal For plugin handling
	virtual PluginReceiveResult OnReceive(Packet *packet);
	virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );

	enum NATDetectionState
	{
		STATE_NONE,
		STATE_TESTING_NONE_1,
		STATE_TESTING_NONE_2,
		STATE_TESTING_FULL_CONE_1,
		STATE_TESTING_FULL_CONE_2,
		STATE_TESTING_ADDRESS_RESTRICTED_1,
		STATE_TESTING_ADDRESS_RESTRICTED_2,
		STATE_TESTING_PORT_RESTRICTED_1,
		STATE_TESTING_PORT_RESTRICTED_2,
		STATE_DONE,
	};

	struct NATDetectionAttempt
	{
		SystemAddress systemAddress;
		NATDetectionState detectionState;
		RakNet::TimeMS nextStateTime;
		RakNet::TimeMS timeBetweenAttempts;
		unsigned short c2Port;
		RakNetGUID guid;
	};

	virtual void OnRNS2Recv(RNS2RecvStruct *recvStruct);
	virtual void DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line);
	virtual RNS2RecvStruct *AllocRNS2RecvStruct(const char *file, unsigned int line);
protected:
	DataStructures::Queue<RNS2RecvStruct*> bufferedPackets;
	SimpleMutex bufferedPacketsMutex;

	void OnDetectionRequest(Packet *packet);
	DataStructures::List<NATDetectionAttempt> natDetectionAttempts;
	unsigned int GetDetectionAttemptIndex(const SystemAddress &sa);
	unsigned int GetDetectionAttemptIndex(RakNetGUID guid);

	// s1p1 is rakpeer itself
	RakNetSocket2 *s1p2,*s2p3,*s3p4,*s4p5;
	//unsigned short s1p2Port, s2p3Port, s3p4Port, s4p5Port;
	char s3p4Address[64];
};

17、TCP接口

struct RemoteClient //存储有关远程客户端的信息
{
	RemoteClient() {
#if OPEN_SSL_CLIENT_SUPPORT==1
		ssl=0;
#endif
		isActive=false;
#if !defined(WINDOWS_STORE_RT)
		socket=0;
#endif
	}
	__TCPSOCKET__ socket;
	SystemAddress systemAddress;
	DataStructures::ByteQueue outgoingData;
	bool isActive;
	SimpleMutex outgoingDataMutex;
	SimpleMutex isActiveMutex;

#if OPEN_SSL_CLIENT_SUPPORT==1
	SSL*     ssl;
	bool InitSSL(SSL_CTX* ctx, SSL_METHOD *meth);
	void DisconnectSSL(void);
	void FreeSSL(void);
	int Send(const char *data, unsigned int length);
	int Recv(char *data, const int dataSize);
#else
	int Send(const char *data, unsigned int length);
	int Recv(char *data, const int dataSize);
#endif
	void Reset(void)
	{
		outgoingDataMutex.Lock();
		outgoingData.Clear(_FILE_AND_LINE_);
		outgoingDataMutex.Unlock();
	}
	void SetActive(bool a);
	void SendOrBuffer(const char **data, const unsigned int *lengths, const int numParameters);
};

实现类:

class RAK_DLL_EXPORT TCPInterface //简单的TCP服务器多线程

18、RPC4插件

	enum RPCErrorCodes //错误码
	{
		/// Named function was not registered with RegisterFunction(). Check your spelling.
		RPC_ERROR_FUNCTION_NOT_REGISTERED,
	};

	/// \brief Instantiate this class globally if you want to register a function with RPC4 at the global space
	class RAK_DLL_EXPORT RPC4GlobalRegistration //记录
	{
	public:
		/// \brief Queue a call to RPC4::RegisterFunction() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
		RPC4GlobalRegistration(const char* uniqueID, void ( *functionPointer ) ( RakNet::BitStream *userData, Packet *packet ));

		/// \brief Queue a call to RPC4::RegisterSlot() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
		RPC4GlobalRegistration(const char* uniqueID, void ( *functionPointer ) ( RakNet::BitStream *userData, Packet *packet ), int callPriority);

		/// \brief Queue a call to RPC4::RegisterBlockingFunction() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
		RPC4GlobalRegistration(const char* uniqueID, void ( *functionPointer ) ( RakNet::BitStream *userData, RakNet::BitStream *returnData, Packet *packet ));

		/// \brief Queue a call to RPC4::RegisterLocalCallback() globally. Actual call occurs once RPC4 is attached to an instance of RakPeer or TCPInterface.
		RPC4GlobalRegistration(const char* uniqueID, MessageID messageId);
	};
实现类:

	class RAK_DLL_EXPORT RPC4 : public PluginInterface2

19、补丁更新

定义结构:

enum PatchContext
{
	PC_HASH_1_WITH_PATCH, //hash值
	PC_HASH_2_WITH_PATCH,
	PC_WRITE_FILE, //写入文件
	PC_ERROR_FILE_WRITE_FAILURE, //写入文件失败
	PC_ERROR_PATCH_TARGET_MISSING, //目标文件丢失
	PC_ERROR_PATCH_APPLICATION_FAILURE, //失败
	PC_ERROR_PATCH_RESULT_CHECKSUM_FAILURE, //检测失败
	PC_NOTICE_WILL_COPY_ON_RESTART, //通知重新拷贝
	PC_NOTICE_FILE_DOWNLOADED, //通知文件下载
	PC_NOTICE_FILE_DOWNLOADED_PATCH, //通知文件下载更新
};
实现类:

class AutopatcherRepositoryInterface : public IncrementalReadInterface
{
public:
	/// Get list of files added and deleted since a certain date.  This is used by AutopatcherServer and not usually explicitly called.
	/// \param[in] applicationName A null terminated string identifying the application
	/// \param[out] addedFiles A list of the current versions of filenames with hashes as their data that were created after \a sinceData
	/// \param[out] deletedFiles A list of the current versions of filenames that were deleted after \a sinceData
	/// \param[in] An input date, in whatever format your repository uses
	/// \param[out] currentDate The current server date, in whatever format your repository uses
	/// \return True on success, false on failure.
	//获取改变的数据
	virtual bool GetChangelistSinceDate(const char *applicationName, FileList *addedOrModifiedFilesWithHashData, FileList *deletedFiles, double sinceDate)=0;

	/// Get patches (or files) for every file in input, assuming that input has a hash for each of those files.
	/// \param[in] applicationName A null terminated string identifying the application
	/// \param[in] input A list of files with SHA1_LENGTH byte hashes to get from the database.
	/// \param[out] patchList You should return list of files with either the filedata or the patch.  This is a subset of \a input.  The context data for each file will be either PC_WRITE_FILE (to just write the file) or PC_HASH_WITH_PATCH (to patch).  If PC_HASH_WITH_PATCH, then the file contains a SHA1_LENGTH byte patch followed by the hash.  The datalength is patchlength + SHA1_LENGTH
	/// \param[out] currentDate The current server date, in whatever format your repository uses
	/// \return 1 on success, 0 on database failure, -1 on tried to download original unmodified file
	//获取补丁包
	virtual int GetPatches(const char *applicationName, FileList *input, bool allowDownloadOfOriginalUnmodifiedFiles, FileList *patchList)=0;

	/// For the most recent update, return files that were patched, added, or deleted. For files that were patched, return both the patch in \a patchedFiles and the current version in \a updatedFiles
	/// \param[in,out] applicationName Name of the application to get patches for. If empty, uses the most recently updated application, and the string will be updated to reflect this name.
	/// \param[out] patchedFiles A list of patched files with op PC_HASH_2_WITH_PATCH. It has 2 hashes, the priorHash and the currentHash. The currentHash is checked on the client after patching for patch success. The priorHash is checked in AutopatcherServer::OnGetPatch() to see if the client is able to hash with the version they currently have
	/// \param[out] patchedFiles A list of new files. It contains the actual data in addition to the filename
	/// \param[out] addedOrModifiedFileHashes A list of file hashes that were either modified or new. This is returned to the client when replying to ID_AUTOPATCHER_CREATION_LIST, which tells the client what files have changed on the server since a certain date
	/// \param[out] deletedFiles A list of the current versions of filenames that were deleted in the most recent patch
	/// \param[out] whenPatched time in seconds since epoch when patched. Use time() function to get this in C
	/// \return true on success, false on failure
	//获取补丁
	virtual bool GetMostRecentChangelistWithPatches(
		RakNet::RakString &applicationName,
		FileList *patchedFiles,
		FileList *updatedFiles,
		FileList *addedOrModifiedFileHashes,
		FileList *deletedFiles,
		double *priorRowPatchTime,
		double *mostRecentRowPatchTime)=0;

	/// \return Whatever this function returns is sent from the AutopatcherServer to the AutopatcherClient when one of the above functions returns false.
	//获取最近的错误
	virtual const char *GetLastError(void) const=0;

	/// \return Passed to FileListTransfer::Send() as the _chunkSize parameter.
	//获取增量数据
	virtual const int GetIncrementalReadChunkSize(void) const=0;
};

20、路由器

内部结构:

	enum Router2RequestStates
	{
		R2RS_REQUEST_STATE_QUERY_FORWARDING,
		REQUEST_STATE_REQUEST_FORWARDING,
	};

	struct ConnectionRequestSystem
	{
		RakNetGUID guid;
		int pingToEndpoint;
		unsigned short usedForwardingEntries;
	};

	struct ConnnectRequest
	{
		ConnnectRequest();
		~ConnnectRequest();

		DataStructures::List<ConnectionRequestSystem> connectionRequestSystems;
		SimpleMutex connectionRequestSystemsMutex;
		Router2RequestStates requestState;
		RakNet::TimeMS pingTimeout;
		RakNetGUID endpointGuid;
		RakNetGUID lastRequestedForwardingSystem;
		bool returnConnectionLostOnFailure;
		unsigned int GetGuidIndex(RakNetGUID guid);
	};

	struct MiniPunchRequest
	{
		RakNetGUID endpointGuid;
		SystemAddress endpointAddress;
		bool gotReplyFromEndpoint;
		RakNetGUID sourceGuid;
		SystemAddress sourceAddress;
		bool gotReplyFromSource;
		RakNet::TimeMS timeout;
		RakNet::TimeMS nextAction;
		unsigned short forwardingPort;
		__UDPSOCKET__ forwardingSocket;
	};

	struct ForwardedConnection
	{
		RakNetGUID endpointGuid;
		RakNetGUID intermediaryGuid;
		SystemAddress intermediaryAddress;
		bool returnConnectionLostOnFailure;
		bool weInitiatedForwarding;
	};
class RAK_DLL_EXPORT Router2 : public PluginInterface2 //通过一个共享的连接路由连接系统
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(Router2)

	Router2();
	virtual ~Router2();

	/// Sets the socket family to use, either IPV4 or IPV6
	/// \param[in] socketFamily For IPV4, use AF_INET (default). For IPV6, use AF_INET6. To autoselect, use AF_UNSPEC.
	void SetSocketFamily(unsigned short _socketFamily);

	/// \note The SystemAddress for a connection should not be used - always use RakNetGuid as the address can change at any time.
	/// When the address changes, you will get ID_ROUTER_2_REROUTED
	void EstablishRouting(RakNetGUID endpointGuid);

	/// Set the maximum number of bidirectional connections this system will support
	/// Defaults to 0
	void SetMaximumForwardingRequests(int max);

	/// For testing and debugging
	void SetDebugInterface(Router2DebugInterface *_debugInterface);

	/// Get the pointer passed to SetDebugInterface()
	Router2DebugInterface *GetDebugInterface(void) const;

	// --------------------------------------------------------------------------------------------
	// Packet handling functions
	// --------------------------------------------------------------------------------------------
	virtual PluginReceiveResult OnReceive(Packet *packet);
	virtual void Update(void);
	virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
	virtual void OnFailedConnectionAttempt(Packet *packet, PI2_FailedConnectionAttemptReason failedConnectionAttemptReason);
	virtual void OnRakPeerShutdown(void);

	unsigned int GetConnectionRequestIndex(RakNetGUID endpointGuid);

protected:

	bool UpdateForwarding(ConnnectRequest* connectionRequest);
	void RemoveConnectionRequest(unsigned int connectionRequestIndex);
	void RequestForwarding(ConnnectRequest* connectionRequest);
	void OnQueryForwarding(Packet *packet);
	void OnQueryForwardingReply(Packet *packet);
	void OnRequestForwarding(Packet *packet);
	void OnRerouted(Packet *packet);
	void OnMiniPunchReply(Packet *packet);
	void OnMiniPunchReplyBounce(Packet *packet);
	bool OnForwardingSuccess(Packet *packet);
	int GetLargestPingAmongConnectedSystems(void) const;
	void ReturnToUser(MessageID messageId, RakNetGUID endpointGuid, const SystemAddress &systemAddress, bool wasGeneratedLocally);
	bool ConnectInternal(RakNetGUID endpointGuid, bool returnConnectionLostOnFailure);

	UDPForwarder *udpForwarder;
	int maximumForwardingRequests;
	SimpleMutex connectionRequestsMutex, miniPunchesInProgressMutex, forwardedConnectionListMutex;
	DataStructures::List<ConnnectRequest*> connectionRequests;
	DataStructures::List<MiniPunchRequest> miniPunchesInProgress;
	// Forwarding we have initiated
	DataStructures::List<ForwardedConnection> forwardedConnectionList;

	void ClearConnectionRequests(void);
	void ClearMinipunches(void);
	void ClearForwardedConnections(void);
	void ClearAll(void);
	int ReturnFailureOnCannotForward(RakNetGUID sourceGuid, RakNetGUID endpointGuid);
	void SendFailureOnCannotForward(RakNetGUID sourceGuid, RakNetGUID endpointGuid);
	void SendForwardingSuccess(MessageID messageId, RakNetGUID sourceGuid, RakNetGUID endpointGuid, unsigned short sourceToDstPort);
	void SendOOBFromRakNetPort(OutOfBandIdentifiers oob, BitStream *extraData, SystemAddress sa);
	void SendOOBFromSpecifiedSocket(OutOfBandIdentifiers oob, SystemAddress sa, __UDPSOCKET__ socket);
	void SendOOBMessages(MiniPunchRequest *mpr);

	Router2DebugInterface *debugInterface;
	unsigned short socketFamily;
};
实例:

	/// RakNet::BitStream bs(packet->data, packet->length, false);
	/// bs.IgnoreBytes(sizeof(MessageID));
	/// RakNetGUID endpointGuid;
	/// bs.Read(endpointGuid);
	/// unsigned short sourceToDestPort;
	/// bs.Read(sourceToDestPort);
	/// char ipAddressString[32];
	/// packet->systemAddress.ToString(false, ipAddressString);
	/// rakPeerInterface->EstablishRouting(ipAddressString, sourceToDestPort, 0,0);

21、延迟插件

enum RelayPluginEnums
{
	// Server handled messages
	RPE_MESSAGE_TO_SERVER_FROM_CLIENT,
	RPE_ADD_CLIENT_REQUEST_FROM_CLIENT,
	RPE_REMOVE_CLIENT_REQUEST_FROM_CLIENT,
	RPE_GROUP_MESSAGE_FROM_CLIENT,
	RPE_JOIN_GROUP_REQUEST_FROM_CLIENT,
	RPE_LEAVE_GROUP_REQUEST_FROM_CLIENT,
	RPE_GET_GROUP_LIST_REQUEST_FROM_CLIENT,
	// Client handled messages
	RPE_MESSAGE_TO_CLIENT_FROM_SERVER,
	RPE_ADD_CLIENT_NOT_ALLOWED,
	RPE_ADD_CLIENT_TARGET_NOT_CONNECTED,
	RPE_ADD_CLIENT_NAME_ALREADY_IN_USE,
	RPE_ADD_CLIENT_SUCCESS,
	RPE_USER_ENTERED_ROOM,
	RPE_USER_LEFT_ROOM,
	RPE_GROUP_MSG_FROM_SERVER,
	RPE_GET_GROUP_LIST_REPLY_FROM_SERVER,
	RPE_JOIN_GROUP_SUCCESS,
	RPE_JOIN_GROUP_FAILURE,
};
内部结构:

	struct StrAndGuidAndRoom
	{
		RakString str;
		RakNetGUID guid;
		RakString currentRoom;
	};

	struct StrAndGuid
	{
		RakString str;
		RakNetGUID guid;
	};

	struct RP_Group
	{
		RakString roomName;
		DataStructures::List<StrAndGuid> usersInRoom;
	};
实现类:

class RAK_DLL_EXPORT RelayPlugin : public PluginInterface2 //通过一个字符串的识别远程系统
关键成员:

	DataStructures::Hash<RakString, StrAndGuidAndRoom*, 8096, RakNet::RakString::ToInteger> strToGuidHash;
	DataStructures::Hash<RakNetGUID, StrAndGuidAndRoom*, 8096, RakNet::RakNetGUID::ToUint32> guidToStrHash;
	DataStructures::List<RP_Group*> chatRooms;
	bool acceptAddParticipantRequests;

22、文件传输

class FileListTransferCBInterface //文件传输回调接口
{
public:
	// Note: If this structure is changed the struct in the swig files need to be changed as well
	struct OnFileStruct
	{
		/// \brief The index into the set of files, from 0 to numberOfFilesInThisSet
		unsigned fileIndex;

		/// \brief The name of the file
		char fileName[512];

		/// \brief The data pointed to by the file
		char *fileData;

		/// \brief The amount of data to be downloaded for this file
		BitSize_t byteLengthOfThisFile;

		/// \brief How many bytes of this file has been downloaded
		BitSize_t bytesDownloadedForThisFile;

		/// \brief Files are transmitted in sets, where more than one set of files can be transmitted at the same time.
		/// \details This is the identifier for the set, which is returned by FileListTransfer::SetupReceive
		unsigned short setID;

		/// \brief The number of files that are in this set.
		unsigned numberOfFilesInThisSet;

		/// \brief The total length of the transmitted files for this set, after being uncompressed
		unsigned byteLengthOfThisSet;

		/// \brief The total length, in bytes, downloaded for this set.
		unsigned bytesDownloadedForThisSet;

		/// \brief User data passed to one of the functions in the FileList class.
		/// \details However, on error, this is instead changed to one of the enumerations in the PatchContext structure.
		FileListNodeContext context;

		/// \brief Who sent this file
		SystemAddress senderSystemAddress;

		/// \brief Who sent this file. Not valid when using TCP, only RakPeer (UDP)
		RakNetGUID senderGuid;
	};

	// Note: If this structure is changed the struct in the swig files need to be changed as well
	struct FileProgressStruct
	{
		/// \param[out] onFileStruct General information about this file, such as the filename and the first \a partLength bytes. You do NOT need to save this data yourself. The complete file will arrive normally.
		OnFileStruct *onFileStruct;
		/// \param[out] partCount The zero based index into partTotal. The percentage complete done of this file is 100 * (partCount+1)/partTotal
		unsigned int partCount;
		/// \param[out] partTotal The total number of parts this file was split into. Each part will be roughly the MTU size, minus the UDP header and RakNet headers
		unsigned int partTotal;
		/// \param[out] dataChunkLength How many bytes long firstDataChunk and iriDataChunk are
		unsigned int dataChunkLength;
		/// \param[out] firstDataChunk The first \a partLength of the final file. If you store identifying information about the file in the first \a partLength bytes, you can read them while the download is taking place. If this hasn‘t arrived yet, firstDataChunk will be 0
		char *firstDataChunk;
		/// \param[out] iriDataChunk If the remote system is sending this file using IncrementalReadInterface, then this is the chunk we just downloaded. It will not exist in memory after this callback. You should either store this to disk, or in memory. If it is 0, then the file is smaller than one chunk, and will be held in memory automatically
		char *iriDataChunk;
		/// \param[out] iriWriteOffset Offset in bytes from the start of the file for the data pointed to by iriDataChunk
		unsigned int iriWriteOffset;
		/// \param[out] Who sent this file
		SystemAddress senderSystemAddress;
		/// \param[out] Who sent this file. Not valid when using TCP, only RakPeer (UDP)
		RakNetGUID senderGuid;
		/// \param[in] allocateIrIDataChunkAutomatically If true, then RakNet will hold iriDataChunk for you and return it in OnFile. Defaults to true
		bool allocateIrIDataChunkAutomatically;
	};

	struct DownloadCompleteStruct
	{
		/// \brief Files are transmitted in sets, where more than one set of files can be transmitted at the same time.
		/// \details This is the identifier for the set, which is returned by FileListTransfer::SetupReceive
		unsigned short setID;

		/// \brief The number of files that are in this set.
		unsigned numberOfFilesInThisSet;

		/// \brief The total length of the transmitted files for this set, after being uncompressed
		unsigned byteLengthOfThisSet;

		/// \brief Who sent this file
		SystemAddress senderSystemAddress;

		/// \brief Who sent this file. Not valid when using TCP, only RakPeer (UDP)
		RakNetGUID senderGuid;
	};

	FileListTransferCBInterface() {}
	virtual ~FileListTransferCBInterface() {}

	/// \brief Got a file.
	/// \details This structure is only valid for the duration of this function call.
	/// \return Return true to have RakNet delete the memory allocated to hold this file for this function call.
	virtual bool OnFile(OnFileStruct *onFileStruct)=0;

	/// \brief Got part of a big file internally in RakNet
	/// \details This is called in one of two circumstances: Either the transport layer is returning ID_PROGRESS_NOTIFICATION, or you got a block via IncrementalReadInterface
	/// If the transport layer is returning ID_PROGRESS_NOTIFICATION (see RakPeer::SetSplitMessageProgressInterval()) then FileProgressStruct::iriDataChunk will be 0.
	/// If this is a block via IncrementalReadInterface, then iriDataChunk will point to the block just downloaded.
	/// If not using IncrementalReadInterface, then you only care about partCount and partTotal to tell how far the download has progressed. YOu can use firstDataChunk to read the first part of the file if desired. The file is usable when you get the OnFile callback.
	/// If using IncrementalReadInterface and you let RakNet buffer the files in memory (default), then it is the same as above. The file is usable when you get the OnFile callback.
	/// If using IncrementalReadInterface and you do not let RakNet buffer the files in memory, then set allocateIrIDataChunkAutomatically to false. Write the file to disk whenever you get OnFileProgress and iriDataChunk is not 0, and ignore OnFile.
	virtual void OnFileProgress(FileProgressStruct *fps)=0;

	/// \brief Called while the handler is active by FileListTransfer
	/// \details Return false when you are done with the class.
	/// At that point OnDereference will be called and the class will no longer be maintained by the FileListTransfer plugin.
	virtual bool Update(void) {return true;}

	/// \brief Called when the download is completed.
	/// \details If you are finished with this class, return false.
	/// At that point OnDereference will be called and the class will no longer be maintained by the FileListTransfer plugin.
	/// Otherwise return true, and Update will continue to be called.
	virtual bool OnDownloadComplete(DownloadCompleteStruct *dcs) {(void) dcs; return false;}

	/// \brief This function is called when this instance is about to be dereferenced by the FileListTransfer plugin.
	/// \details Update will no longer be called.
	/// It will will be deleted automatically if true was passed to FileListTransfer::SetupReceive::deleteHandler
	/// Otherwise it is up to you to delete it yourself.
	virtual void OnDereference(void) {}
};
内部结构:

	struct FileToPush
	{
		FileListNode fileListNode;
		PacketPriority packetPriority;
		char orderingChannel;
		unsigned int currentOffset;
		////unsigned short setID;
		unsigned int setIndex;
		IncrementalReadInterface *incrementalReadInterface;
		unsigned int chunkSize;
	};
	struct FileToPushRecipient
	{
		unsigned int refCount;
		SimpleMutex refCountMutex;
		void DeleteThis(void);
		void AddRef(void);
		void Deref(void);

		SystemAddress systemAddress;
		unsigned short setId;

		//// SimpleMutex filesToPushMutex;
		DataStructures::Queue<FileToPush*> filesToPush;
	};
	struct ThreadData
	{
		FileListTransfer *fileListTransfer;
		SystemAddress systemAddress;
		unsigned short setId;
	};
实现类:

class RAK_DLL_EXPORT FileListTransfer : public PluginInterface2

23、控制服务器

class RAK_DLL_EXPORT ConsoleServer //远程控制台应用程序
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(ConsoleServer)

	ConsoleServer();
	~ConsoleServer();

	/// \brief Call this with a derivation of TransportInterface so that the console server can send and receive commands
	/// \param[in] transportInterface Your interface to use.
	/// \param[in] port The port to host on.  Telnet uses port 23 by default.  RakNet can use whatever you want.
	void SetTransportProvider(TransportInterface *transportInterface, unsigned short port);

	/// \brief Add an implementation of CommandParserInterface to the list of command parsers.
	/// \param[in] commandParserInterface The command parser referred to
	void AddCommandParser(CommandParserInterface *commandParserInterface);

	/// \brief Remove an implementation of CommandParserInterface previously added with AddCommandParser().
	/// \param[in] commandParserInterface The command parser referred to
	void RemoveCommandParser(CommandParserInterface *commandParserInterface);

	/// \brief Call update to read packet sent from your TransportInterface.
	/// You should do this fairly frequently.
	void Update(void);

	/// \brief Sets a prompt to show when waiting for user input.
	/// \details Pass an empty string to clear the prompt
	/// Defaults to no prompt
	/// \param[in] _prompt Null-terminated string of the prompt to use. If you want a newline, be sure to use /r/n
	void SetPrompt(const char *_prompt);

protected:
	void ListParsers(SystemAddress systemAddress);
	void ShowPrompt(SystemAddress systemAddress);
	TransportInterface *transport;
	DataStructures::List<CommandParserInterface *> commandParserList;
	char* password[256];
	char *prompt;
};

24、连接图

class RAK_DLL_EXPORT ConnectionGraph2 : public PluginInterface2 //跳转连接图插件
{
public:

	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(ConnectionGraph2)

	ConnectionGraph2();
	~ConnectionGraph2();

	/// \brief Given a remote system identified by RakNetGUID, return the list of SystemAddresses and RakNetGUIDs they are connected to 
	/// \param[in] remoteSystemGuid Which system we are referring to. This only works for remote systems, not ourselves.
	/// \param[out] saOut A preallocated array to hold the output list of SystemAddress. Can be 0 if you don‘t care.
	/// \param[out] guidOut A preallocated array to hold the output list of RakNetGUID. Can be 0 if you don‘t care.
	/// \param[in,out] outLength On input, the size of \a saOut and \a guidOut. On output, modified to reflect the number of elements actually written
	/// \return True if \a remoteSystemGuid was found. Otherwise false, and \a saOut, \a guidOut remain unchanged. \a outLength will be set to 0.
	bool GetConnectionListForRemoteSystem(RakNetGUID remoteSystemGuid, SystemAddress *saOut, RakNetGUID *guidOut, unsigned int *outLength);

	/// Returns if g1 is connected to g2
	bool ConnectionExists(RakNetGUID g1, RakNetGUID g2);

	/// Returns the average ping between two systems in the connection graph. Returns -1 if no connection exists between those systems
	uint16_t GetPingBetweenSystems(RakNetGUID g1, RakNetGUID g2) const;

	/// Returns the system with the lowest average ping among all its connections.
	/// If you need one system in the peer to peer group to relay data, have the FullyConnectedMesh2 host call this function after host migration, and use that system
	RakNetGUID GetLowestAveragePingSystem(void) const;

	/// \brief If called with false, then new connections are only added to the connection graph when you call ProcessNewConnection();
	/// \details This is useful if you want to perform validation before connecting a system to a mesh, or if you want a submesh (for example a server cloud)
	/// \param[in] b True to automatically call ProcessNewConnection() on any new connection, false to not do so. Defaults to true.
	void SetAutoProcessNewConnections(bool b);

	/// \brief Returns value passed to SetAutoProcessNewConnections()
	/// \return Value passed to SetAutoProcessNewConnections(), or the default of true if it was never called
	bool GetAutoProcessNewConnections(void) const;

	/// \brief If you call SetAutoProcessNewConnections(false);, then you will need to manually call ProcessNewConnection() on new connections
	/// \details On ID_NEW_INCOMING_CONNECTION or ID_CONNECTION_REQUEST_ACCEPTED, adds that system to the graph
	/// Do not call ProcessNewConnection() manually otherwise
	/// \param[in] The packet->SystemAddress member
	/// \param[in] The packet->guid member
	void AddParticipant(const SystemAddress &systemAddress, RakNetGUID rakNetGUID);

	/// Get the participants added with AddParticipant()
	/// \param[out] participantList Participants added with AddParticipant();
	void GetParticipantList(DataStructures::OrderedList<RakNetGUID, RakNetGUID> &participantList);

	/// \internal
	struct SystemAddressAndGuid
	{
		SystemAddress systemAddress;
		RakNetGUID guid;
		uint16_t sendersPingToThatSystem;
	};
	/// \internal
	static int SystemAddressAndGuidComp( const SystemAddressAndGuid &key, const SystemAddressAndGuid &data );

	/// \internal
	struct RemoteSystem
	{
		DataStructures::OrderedList<SystemAddressAndGuid,SystemAddressAndGuid,ConnectionGraph2::SystemAddressAndGuidComp> remoteConnections;
		RakNetGUID guid;
	};
	/// \internal
	static int RemoteSystemComp( const RakNetGUID &key, RemoteSystem * const &data );
	
protected:
	/// \internal
	virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
	/// \internal
	virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);
	/// \internal
	virtual PluginReceiveResult OnReceive(Packet *packet);

	// List of systems I am connected to, which in turn stores which systems they are connected to
	DataStructures::OrderedList<RakNetGUID, RemoteSystem*, ConnectionGraph2::RemoteSystemComp> remoteSystems;

	bool autoProcessNewConnections;

};

25、云端

云端有服务端和客户端之分。

class RAK_DLL_EXPORT CloudAllocator //远端生成
{
public:
	CloudAllocator() {}
	virtual ~CloudAllocator() {}

	/// \brief Allocate a row
	virtual CloudQueryRow* AllocateCloudQueryRow(void);
	/// \brief Free a row
	virtual void DeallocateCloudQueryRow(CloudQueryRow *row);
	/// \brief Allocate CloudQueryRow::data
	virtual unsigned char *AllocateRowData(uint32_t bytesNeededForData);
	/// \brief Free CloudQueryRow::data
	virtual void DeallocateRowData(void *data);
};
struct RAK_DLL_EXPORT CloudKey //云端密钥
{
	CloudKey() {}
	CloudKey(RakNet::RakString _primaryKey, uint32_t _secondaryKey) : primaryKey(_primaryKey), secondaryKey(_secondaryKey) {}
	~CloudKey() {}

	/// Identifies the primary key. This is intended to be a major category, such as the name of the application
	/// Must be non-empty
	RakNet::RakString primaryKey;

	/// Identifies the secondary key. This is intended to be a subcategory enumeration, such as PLAYER_LIST or RUNNING_SCORES
	uint32_t secondaryKey;

	/// \internal
	void Serialize(bool writeToBitstream, BitStream *bitStream);
};
struct RAK_DLL_EXPORT CloudQuery //云端查询
{
	CloudQuery() {startingRowIndex=0; maxRowsToReturn=0; subscribeToResults=false;}

	/// List of keys to query. Must be at least of length 1.
	/// This query is run on uploads from all clients, and those that match the combination of primaryKey and secondaryKey are potentially returned
	/// If you pass more than one key at a time, the results are concatenated so if you need to differentiate between queries then send two different queries
	DataStructures::List<CloudKey> keys;

	/// If limiting the number of rows to return, this is the starting offset into the list. Has no effect unless maxRowsToReturn is > 0
	uint32_t startingRowIndex;

	/// Maximum number of rows to return. Actual number may still be less than this. Pass 0 to mean no-limit.
	uint32_t maxRowsToReturn;

	/// If true, automatically get updates as the results returned to you change. Unsubscribe with CloudMemoryClient::Unsubscribe()
	bool subscribeToResults;

	/// \internal
	void Serialize(bool writeToBitstream, BitStream *bitStream);
};
struct RAK_DLL_EXPORT CloudQueryRow //云端查询节点
{
	/// Key used to identify this data
	CloudKey key;

	/// Data uploaded
	unsigned char *data;

	/// Length of data uploaded
	uint32_t length;

	/// System address of server that is holding this data, and the client is connected to
	SystemAddress serverSystemAddress;

	/// System address of client that uploaded this data
	SystemAddress clientSystemAddress;

	/// RakNetGUID of server that is holding this data, and the client is connected to
	RakNetGUID serverGUID;

	/// RakNetGUID of client that uploaded this data
	RakNetGUID clientGUID;

	/// \internal
	void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator);
};
struct RAK_DLL_EXPORT CloudQueryResult //云端查询结果
{
	/// Query originally passed to Download()
	CloudQuery cloudQuery;

	/// Results returned from query. If there were multiple keys in CloudQuery::keys then see resultKeyIndices
	DataStructures::List<CloudQueryRow*> rowsReturned;

	/// If there were multiple keys in CloudQuery::keys, then each key is processed in order and the result concatenated to rowsReturned
	/// The starting index of each query is written to resultKeyIndices
	/// For example, if CloudQuery::keys had 4 keys, returning 3 rows, 0, rows, 5 rows, and 12 rows then
	/// resultKeyIndices would be 0, 3, 3, 8
	DataStructures::List<uint32_t> resultKeyIndices;

	/// Whatever was passed to CloudClient::Get() as CloudQuery::subscribeToResults
	bool subscribeToResults;

	/// \internal
	void Serialize(bool writeToBitstream, BitStream *bitStream, CloudAllocator *allocator);
	/// \internal
	void SerializeHeader(bool writeToBitstream, BitStream *bitStream);
	/// \internal
	void SerializeNumRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream);
	/// \internal
	void SerializeCloudQueryRows(bool writeToBitstream, uint32_t &numRows, BitStream *bitStream, CloudAllocator *allocator);
};
客户端有回调类:

class RAK_DLL_EXPORT CloudClientCallback
{
public:
	CloudClientCallback() {}
	virtual ~CloudClientCallback() {}

	/// \brief Called in response to ID_CLOUD_GET_RESPONSE
	/// \param[out] result Contains the original query passed to Get(), and a list of rows returned.
	/// \param[out] deallocateRowsAfterReturn CloudQueryResult::rowsReturned will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator.
	virtual void OnGet(RakNet::CloudQueryResult *result, bool *deallocateRowsAfterReturn) {(void) result; (void) deallocateRowsAfterReturn;}

	/// \brief Called in response to ID_CLOUD_SUBSCRIPTION_NOTIFICATION
	/// \param[out] result Contains the row updated
	/// \param[out] wasUpdated If true, the row was updated. If false, it was deleted. \a result will contain the last value just before deletion
	/// \param[out] deallocateRowAfterReturn \a result will be deallocated after the function returns by default. Set to false to not deallocate these pointers. The pointers are allocated through CloudAllocator.
	virtual void OnSubscriptionNotification(RakNet::CloudQueryRow *result, bool wasUpdated, bool *deallocateRowAfterReturn) {(void) result; (void) wasUpdated; (void) deallocateRowAfterReturn;}
};

客户端实现类:

class RAK_DLL_EXPORT CloudClient : public PluginInterface2

服务端有查询过滤类:

class RAK_DLL_EXPORT CloudServerQueryFilter
{
public:
	CloudServerQueryFilter() {}
	virtual ~CloudServerQueryFilter() {}

	/// Called when a local client wants to post data
	/// \return true to allow, false to reject
	virtual bool OnPostRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudKey key, uint32_t dataLength, const char *data)=0;

	/// Called when a local client wants to release data that it has previously uploaded
	/// \return true to allow, false to reject
	virtual bool OnReleaseRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys)=0;

	/// Called when a local client wants to query data
	/// If you return false, the client will get no response at all
	/// \return true to allow, false to reject
	virtual bool OnGetRequest(RakNetGUID clientGuid, SystemAddress clientAddress, CloudQuery &query, DataStructures::List<RakNetGUID> &specificSystems)=0;

	/// Called when a local client wants to stop getting updates for data
	/// If you return false, the client will keep getting updates for that data
	/// \return true to allow, false to reject
	virtual bool OnUnsubscribeRequest(RakNetGUID clientGuid, SystemAddress clientAddress, DataStructures::List<CloudKey> &cloudKeys, DataStructures::List<RakNetGUID> &specificSystems)=0;
};
服务端实现类:

class RAK_DLL_EXPORT CloudServer : public PluginInterface2, CloudAllocator

26、拷贝管理

enum //复制接口标志,用于启用和禁用的函数调用的复制对象
{
	REPLICA_RECEIVE_DESTRUCTION=1<<0,
	REPLICA_RECEIVE_SERIALIZE=1<<1,
	REPLICA_RECEIVE_SCOPE_CHANGE=1<<2,
	REPLICA_SEND_CONSTRUCTION=1<<3,
	REPLICA_SEND_DESTRUCTION=1<<4,
	REPLICA_SEND_SCOPE_CHANGE=1<<5,
	REPLICA_SEND_SERIALIZE=1<<6,
	REPLICA_SET_ALL = 0xFF // Allow all of the above
};

enum ReplicaReturnResult //复制结果
{
	/// This means call the function again later, with the same parameters
	REPLICA_PROCESS_LATER,
	/// This means we are done processing (the normal result to return)
	REPLICA_PROCESSING_DONE,
	/// This means cancel the processing - don‘t send any network messages and don‘t change the current state.
	REPLICA_CANCEL_PROCESS,
	/// Same as REPLICA_PROCESSING_DONE, where a message is sent, but does not clear the send bit.
	/// Useful for multi-part sends with different reliability levels.
	/// Only currently used by Replica::Serialize
	REPLICA_PROCESS_AGAIN,
	/// Only returned from the Replica::SendConstruction interface, means act as if the other system had this object but don‘t actually
	/// Send a construction packet.  This way you will still send scope and serialize packets to that system
	REPLICA_PROCESS_IMPLICIT
};
有关类:

class RAK_DLL_EXPORT ReplicaManager3 : public PluginInterface2
class RAK_DLL_EXPORT Connection_RM3
class RAK_DLL_EXPORT Replica3 : public NetworkIDObject
template <class parent_type>
class RAK_DLL_EXPORT Replica3Composite : public Replica3

27、饱和连接

内部结构:

	/// \internal
	struct FCM2Participant
	{
		FCM2Participant() {}
		FCM2Participant(const FCM2Guid &_fcm2Guid, const RakNetGUID &_rakNetGuid) : fcm2Guid(_fcm2Guid), rakNetGuid(_rakNetGuid) {}

		// Low half is a random number.
		// High half is the order we connected in (totalConnectionCount)
		FCM2Guid fcm2Guid;
		RakNetGUID rakNetGuid;
		// BitStream userContext;
	};

	enum JoinInProgressState
	{
		JIPS_PROCESSING,
		JIPS_FAILED,
		JIPS_CONNECTED,
		JIPS_UNNECESSARY,
	};

	struct VerifiedJoinInProgressMember
	{
		SystemAddress systemAddress;
		RakNetGUID guid;
		JoinInProgressState joinInProgressState;
		BitStream *userData;

		bool workingFlag;
	};

	/// \internal
	struct VerifiedJoinInProgress
	{
		RakNetGUID requester;
		DataStructures::List<VerifiedJoinInProgressMember> vjipMembers;
		//bool sentResults;
	};
实现类:

class RAK_DLL_EXPORT FullyConnectedMesh2 : public PluginInterface2


测试代码:

Startup()
ourFCMGuid=unknown
totalConnectionCount=0
Set startupTime

AddParticipant()
if (sender by guid is a participant)
return;
AddParticipantInternal(guid);
if (ourFCMGuid==unknown)
Send to that system a request for their fcmGuid, totalConnectionCount. Inform startupTime.
else
Send to that system a request for their fcmGuid. Inform total connection count, our fcmGuid

OnRequestGuid()
if (sender by guid is not a participant)
{
	// They added us as a participant, but we didn‘t add them. This can be caused by lag where both participants are not added at the same time.
	// It doesn‘t affect the outcome as long as we still process the data
	AddParticipantInternal(guid);
}
if (ourFCMGuid==unknown)
{
	if (includedStartupTime)
	{
		// Nobody has a fcmGuid

		if (their startup time is greater than our startup time)
			ReplyConnectionCount(1);
		else
			ReplyConnectionCount(2);
	}
	else
	{
		// They have a fcmGuid, we do not

		SetMaxTotalConnectionCount(remoteCount);
		AssignTheirGuid()
		GenerateOurGuid();
		SendOurGuid(all);
	}
}
else
{
	if (includedStartupTime)
	{
		// We have a fcmGuid they do not

		ReplyConnectionCount(totalConnectionCount+1);
		SendOurGuid(sender);
	}
	else
	{
		// We both have fcmGuids

		SetMaxTotalConnectionCount(remoteCount);
		AssignTheirGuid();
		SendOurGuid(sender);
	}
}

OnReplyConnectionCount()
SetMaxTotalConnectionCount(remoteCount);
GenerateOurGuid();
SendOurGuid(allParticipants);

OnReceiveTheirGuid()
AssignTheirGuid()

28、Http连接

有两个Http封装类:

class RAK_DLL_EXPORT HTTPConnection
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(HTTPConnection)

    /// Returns a HTTP object associated with this tcp connection
    HTTPConnection();
    virtual ~HTTPConnection();

	/// \pre tcp should already be started
	void Init(TCPInterface *_tcp, const char *host, unsigned short port=80);

    /// Submit data to the HTTP server
    /// HTTP only allows one request at a time per connection
    ///
	/// \pre IsBusy()==false
    /// \param path the path on the remote server you want to POST to. For example "index.html"
    /// \param data A NULL terminated string to submit to the server
	/// \param contentType "Content-Type:" passed to post.
    void Post(const char *path, const char *data, const char *_contentType="application/x-www-form-urlencoded");

	/// Get a file from a webserver
	/// \param path the path on the remote server you want to GET from. For example "index.html"
	void Get(const char *path);
    
	/// Is there a Read result ready?
	bool HasRead(void) const;

    /// Get one result from the server
	/// \pre HasResult must return true
    RakNet::RakString Read(void);

	/// Call periodically to do time-based updates
	void Update(void);

	/// Returns the address of the server we are connected to
	SystemAddress GetServerAddress(void) const;

	/// Process an HTTP data packet returned from TCPInterface
	/// Returns true when we have gotten all the data from the HTTP server.
    /// If this returns true then it‘s safe to Post() another request
	/// Deallocate the packet as usual via TCPInterface
    /// \param packet NULL or a packet associated with our host and port
   void ProcessTCPPacket(Packet *packet);

    /// Results of HTTP requests.  Standard response codes are < 999
    /// ( define HTTP codes and our internal codes as needed )
    enum ResponseCodes { NoBody=1001, OK=200, Deleted=1002 };

	HTTPConnection& operator=(const HTTPConnection& rhs){(void) rhs; return *this;}
   
    /// Encapsulates a raw HTTP response and response code
    struct BadResponse
    {
    public:
		BadResponse() {code=0;}
        
        BadResponse(const unsigned char *_data, int _code)
            : data((const char *)_data), code(_code) {}
        
        BadResponse(const char *_data, int _code)
            : data(_data), code(_code) {}

		operator int () const { return code; }

		RakNet::RakString data;
		int code;  // ResponseCodes
    };

    /// Queued events of failed exchanges with the HTTP server
    bool HasBadResponse(int *code, RakNet::RakString *data);

	/// Returns false if the connection is not doing anything else
	bool IsBusy(void) const;

	/// \internal
	int GetState(void) const;

	struct OutgoingCommand
	{
		RakNet::RakString remotePath;
		RakNet::RakString data;
		RakNet::RakString contentType;
		bool isPost;
	};

	 DataStructures::Queue<OutgoingCommand> outgoingCommand;
	 OutgoingCommand currentProcessingCommand;

private:
    SystemAddress server;
    TCPInterface *tcp;
	RakNet::RakString host;
	unsigned short port;
	DataStructures::Queue<BadResponse> badResponses;

	enum ConnectionState
	{
		CS_NONE,
		CS_DISCONNECTING,
		CS_CONNECTING,
		CS_CONNECTED,
		CS_PROCESSING,
	} connectionState;

	RakNet::RakString incomingData;
	DataStructures::Queue<RakNet::RakString> results;

	void CloseConnection();
	
	/*
	enum { RAK_HTTP_INITIAL,
		RAK_HTTP_STARTING,
		RAK_HTTP_CONNECTING,
		RAK_HTTP_ESTABLISHED,
		RAK_HTTP_REQUEST_SENT,
		RAK_HTTP_IDLE } state;

    RakNet::RakString outgoing, incoming, path, contentType;
    void Process(Packet *packet); // the workhorse
    
    // this helps check the various status lists in TCPInterface
	typedef SystemAddress (TCPInterface::*StatusCheckFunction)(void);
	bool InList(StatusCheckFunction func);
	*/

};
class RAK_DLL_EXPORT HTTPConnection2 : public PluginInterface2 //使用插件实现
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(HTTPConnection2)

    HTTPConnection2();
    virtual ~HTTPConnection2();

	/// \brief Connect to, then transmit a request to a TCP based server
	/// \param[in] tcp An instance of TCPInterface that previously had TCPInterface::Start() called
	/// \param[in] stringToTransmit What string to transmit. See RakString::FormatForPOST(), RakString::FormatForGET(), RakString::FormatForDELETE()
	/// \param[in] host The IP address to connect to
	/// \param[in] port The port to connect to
	/// \param[in] useSSL If to use SSL to connect. OPEN_SSL_CLIENT_SUPPORT must be defined to 1 in RakNetDefines.h or RakNetDefinesOverrides.h
	/// \param[in] ipVersion 4 for IPV4, 6 for IPV6
	/// \param[in] useAddress Assume we are connected to this address and send to it, rather than do a lookup
	/// \param[in] userData
	/// \return false if host is not a valid IP address or domain name
	bool TransmitRequest(const char* stringToTransmit, const char* host, unsigned short port=80, bool useSSL=false, int ipVersion=4, SystemAddress useAddress=UNASSIGNED_SYSTEM_ADDRESS, void *userData=http://www.mamicode.com/0);>

29、团队管理

内部结构:

	struct TeamMember
	{
		RakNetGUID memberGuid;
		NetworkID memberId;
		TeamId currentTeam;
		TeamId requestedTeam;
	};
	struct MyTeamMembers
	{
		NetworkID memberId;
		TeamId currentTeam;
		TeamId requestedTeam;
	};
实现类:

class RAK_DLL_EXPORT TeamBalancer : public PluginInterface2 //设置网络和团队的选择(支持对等或客户机/服务器),信息自动处理团
管理部分
enum JoinTeamType
{
	/// Attempt to join the first available team.
	JOIN_ANY_AVAILABLE_TEAM,
	/// Attempt to join a specific team, previously added with TM_World::ReferenceTeam()
	JOIN_SPECIFIC_TEAM,
	/// No team. Always succeeds.
	JOIN_NO_TEAM
};

/// \ingroup TEAM_MANAGER_GROUP
enum TMTopology
{
	// Each system will send all messages to all participants
	TM_PEER_TO_PEER,

	// The host will relay incoming messages to all participants
	TM_CLIENT_SERVER,
};

/// \brief Parameter to TM_World::ReferenceTeamMember()
/// \details Use TeamSelection::AnyAvailable(), TeamSelection::SpecificTeam(), or TeamSelection::NoTeam()
/// \ingroup TEAM_MANAGER_GROUP
struct TeamSelection
{
	TeamSelection();
	TeamSelection(JoinTeamType itt);
	TeamSelection(JoinTeamType itt, TM_Team *param);
	TeamSelection(JoinTeamType itt, NoTeamId param);
	JoinTeamType joinTeamType;
	
	union
	{
		TM_Team *specificTeamToJoin;
		NoTeamId noTeamSubcategory;
	} teamParameter;
	
	/// \brief Join any team that has available slots and is tagged with ALLOW_JOIN_ANY_AVAILABLE_TEAM
	/// \details ID_TEAM_BALANCER_TEAM_ASSIGNED, ID_TEAM_BALANCER_REQUESTED_TEAM_FULL, or ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED will be returned to all systems.
	static TeamSelection AnyAvailable(void);
	/// \brief Join a specific team if it has available slots, and is tagged with JOIN_SPECIFIC_TEAMS
	/// \details ID_TEAM_BALANCER_TEAM_ASSIGNED, ID_TEAM_BALANCER_REQUESTED_TEAM_FULL, or ID_TEAM_BALANCER_REQUESTED_TEAM_LOCKED will be returned to all systems.
	/// \param[in] specificTeamToJoin Which team to attempt to join.
	static TeamSelection SpecificTeam(TM_Team *specificTeamToJoin);
	/// \brief Do not join a team, or leave all current teams.
	/// \details This always succeeds. ID_TEAM_BALANCER_TEAM_ASSIGNED will be returned to all systems.
	/// \param[in] noTeamSubcategory Even when not on a team, you can internally identify a subcategory of not being on a team, such as AI or spectator.
	static TeamSelection NoTeam(NoTeamId noTeamSubcategory);
};
class RAK_DLL_EXPORT TM_TeamMember //包含数据和操作(管理团队、团队成员、你的游戏)
class RAK_DLL_EXPORT TM_Team //一个团队
class TM_World //存储一个团队列表,负责平衡。
class RAK_DLL_EXPORT TeamManager : public PluginInterface2 //自动化网络与团队列表管理

30、UDP代理

UDP代理有服务端和客户端之分

enum UDPProxyMessages //消息类型
{
	ID_UDP_PROXY_FORWARDING_SUCCEEDED,
	ID_UDP_PROXY_FORWARDING_NOTIFICATION,
	ID_UDP_PROXY_NO_SERVERS_ONLINE,
	ID_UDP_PROXY_RECIPIENT_GUID_NOT_CONNECTED_TO_COORDINATOR,
	ID_UDP_PROXY_ALL_SERVERS_BUSY,
	ID_UDP_PROXY_IN_PROGRESS,
	ID_UDP_PROXY_FORWARDING_REQUEST_FROM_CLIENT_TO_COORDINATOR,
	ID_UDP_PROXY_PING_SERVERS_FROM_COORDINATOR_TO_CLIENT,
	ID_UDP_PROXY_PING_SERVERS_REPLY_FROM_CLIENT_TO_COORDINATOR,
	ID_UDP_PROXY_FORWARDING_REQUEST_FROM_COORDINATOR_TO_SERVER,
	ID_UDP_PROXY_FORWARDING_REPLY_FROM_SERVER_TO_COORDINATOR,
	ID_UDP_PROXY_LOGIN_REQUEST_FROM_SERVER_TO_COORDINATOR,
	ID_UDP_PROXY_LOGIN_SUCCESS_FROM_COORDINATOR_TO_SERVER,
	ID_UDP_PROXY_ALREADY_LOGGED_IN_FROM_COORDINATOR_TO_SERVER,
	ID_UDP_PROXY_NO_PASSWORD_SET_FROM_COORDINATOR_TO_SERVER,
	ID_UDP_PROXY_WRONG_PASSWORD_FROM_COORDINATOR_TO_SERVER
};
	class RAK_DLL_EXPORT UDPProxyCoordinator : public PluginInterface2 //代理协调类
	{
	public:
		// GetInstance() and DestroyInstance(instance*)
		STATIC_FACTORY_DECLARATIONS(UDPProxyCoordinator)

		UDPProxyCoordinator();
		virtual ~UDPProxyCoordinator();

		/// For UDPProxyServers logging in remotely, they must pass a password to UDPProxyServer::LoginToCoordinator(). It must match the password set here.
		/// If no password is set, they cannot login remotely.
		/// By default, no password is set
		void SetRemoteLoginPassword(RakNet::RakString password);

		/// \internal
		virtual void Update(void);
		virtual PluginReceiveResult OnReceive(Packet *packet);
		virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );

		struct SenderAndTargetAddress
		{
			SystemAddress senderClientAddress;
			RakNetGUID senderClientGuid;
			SystemAddress targetClientAddress;
			RakNetGUID targetClientGuid;
		};

		struct ServerWithPing
		{
			unsigned short ping;
			SystemAddress serverAddress;
		};

		struct ForwardingRequest
		{
			RakNet::TimeMS timeoutOnNoDataMS;
			RakNet::TimeMS timeoutAfterSuccess;
			SenderAndTargetAddress sata;
			SystemAddress requestingAddress; // Which system originally sent the network message to start forwarding
			SystemAddress currentlyAttemptedServerAddress;
			DataStructures::Queue<SystemAddress> remainingServersToTry;
			RakNet::BitStream serverSelectionBitstream;

			DataStructures::List<ServerWithPing> sourceServerPings, targetServerPings;
			RakNet::TimeMS timeRequestedPings;
			// Order based on sourceServerPings and targetServerPings
			void OrderRemainingServersToTry(void);
		
		};
	protected:

		static int ServerWithPingComp( const unsigned short &key, const UDPProxyCoordinator::ServerWithPing &data );
		static int ForwardingRequestComp( const SenderAndTargetAddress &key, ForwardingRequest* const &data);

		void OnForwardingRequestFromClientToCoordinator(Packet *packet);
		void OnLoginRequestFromServerToCoordinator(Packet *packet);
		void OnForwardingReplyFromServerToCoordinator(Packet *packet);
		void OnPingServersReplyFromClientToCoordinator(Packet *packet);
		void TryNextServer(SenderAndTargetAddress sata, ForwardingRequest *fw);
		void SendAllBusy(SystemAddress senderClientAddress, SystemAddress targetClientAddress, RakNetGUID targetClientGuid, SystemAddress requestingAddress);
		void Clear(void);

		void SendForwardingRequest(SystemAddress sourceAddress, SystemAddress targetAddress, SystemAddress serverAddress, RakNet::TimeMS timeoutOnNoDataMS);

		// Logged in servers
		//DataStructures::Multilist<ML_UNORDERED_LIST, SystemAddress> serverList;
		DataStructures::List<SystemAddress> serverList;

		// Forwarding requests in progress
		//DataStructures::Multilist<ML_ORDERED_LIST, ForwardingRequest*, SenderAndTargetAddress> forwardingRequestList;
		DataStructures::OrderedList<SenderAndTargetAddress, ForwardingRequest*, ForwardingRequestComp> forwardingRequestList;

		RakNet::RakString remoteLoginPassword;
	};
客户端:

struct UDPProxyClientResultHandler //客户端返回
{
	UDPProxyClientResultHandler() {}
	virtual ~UDPProxyClientResultHandler() {}

	/// Called when our forwarding request was completed. We can now connect to \a targetAddress by using \a proxyAddress instead
	/// \param[out] proxyIPAddress IP Address of the proxy server, which will forward messages to targetAddress
	/// \param[out] proxyPort Remote port to use on the proxy server, which will forward messages to targetAddress
	/// \param[out] proxyCoordinator \a proxyCoordinator parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] sourceAddress \a sourceAddress parameter passed to UDPProxyClient::RequestForwarding. If it was UNASSIGNED_SYSTEM_ADDRESS, it is now our external IP address.
	/// \param[out] targetAddress \a targetAddress parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] targetGuid \a targetGuid parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] proxyClient The plugin that is calling this callback
	virtual void OnForwardingSuccess(const char *proxyIPAddress, unsigned short proxyPort,
		SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, RakNet::UDPProxyClient *proxyClientPlugin)=0;

	/// Called when another system has setup forwarding, with our system as the target address.
	/// Plugin automatically sends a datagram to proxyIPAddress before this callback, to open our router if necessary.
	/// \param[out] proxyIPAddress IP Address of the proxy server, which will forward messages to targetAddress
	/// \param[out] proxyPort Remote port to use on the proxy server, which will forward messages to targetAddress
	/// \param[out] proxyCoordinator \a proxyCoordinator parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] sourceAddress \a sourceAddress parameter passed to UDPProxyClient::RequestForwarding. This is originating source IP address of the remote system that will be sending to us.
	/// \param[out] targetAddress \a targetAddress parameter originally passed to UDPProxyClient::RequestForwarding. This is our external IP address.
	/// \param[out] targetGuid \a targetGuid parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] proxyClient The plugin that is calling this callback
	virtual void OnForwardingNotification(const char *proxyIPAddress, unsigned short proxyPort,
		SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, RakNet::UDPProxyClient *proxyClientPlugin)=0;

	/// Called when our forwarding request failed, because no UDPProxyServers are connected to UDPProxyCoordinator
	/// \param[out] proxyCoordinator \a proxyCoordinator parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] sourceAddress \a sourceAddress parameter passed to UDPProxyClient::RequestForwarding. If it was UNASSIGNED_SYSTEM_ADDRESS, it is now our external IP address.
	/// \param[out] targetAddress \a targetAddress parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] targetGuid \a targetGuid parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] proxyClient The plugin that is calling this callback
	virtual void OnNoServersOnline(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, RakNet::UDPProxyClient *proxyClientPlugin)=0;

	/// Called when our forwarding request failed, because no UDPProxyServers are connected to UDPProxyCoordinator
	/// \param[out] proxyCoordinator \a proxyCoordinator parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] sourceAddress \a sourceAddress parameter passed to UDPProxyClient::RequestForwarding. If it was UNASSIGNED_SYSTEM_ADDRESS, it is now our external IP address.
	/// \param[out] targetAddress \a targetAddress parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] targetGuid \a targetGuid parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] proxyClient The plugin that is calling this callback
	virtual void OnRecipientNotConnected(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, RakNet::UDPProxyClient *proxyClientPlugin)=0;

	/// Called when our forwarding request failed, because all UDPProxyServers that are connected to UDPProxyCoordinator are at their capacity
	/// Either add more servers, or increase capacity via UDPForwarder::SetMaxForwardEntries()
	/// \param[out] proxyCoordinator \a proxyCoordinator parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] sourceAddress \a sourceAddress parameter passed to UDPProxyClient::RequestForwarding. If it was UNASSIGNED_SYSTEM_ADDRESS, it is now our external IP address.
	/// \param[out] targetAddress \a targetAddress parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] targetGuid \a targetGuid parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] proxyClient The plugin that is calling this callback
	virtual void OnAllServersBusy(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, RakNet::UDPProxyClient *proxyClientPlugin)=0;

	/// Called when our forwarding request is already in progress on the \a proxyCoordinator.
	/// This can be ignored, but indicates an unneeded second request
	/// \param[out] proxyIPAddress IP Address of the proxy server, which is forwarding messages to targetAddress
	/// \param[out] proxyPort Remote port to use on the proxy server, which is forwarding messages to targetAddress
	/// \param[out] proxyCoordinator \a proxyCoordinator parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] sourceAddress \a sourceAddress parameter passed to UDPProxyClient::RequestForwarding. If it was UNASSIGNED_SYSTEM_ADDRESS, it is now our external IP address.
	/// \param[out] targetAddress \a targetAddress parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] targetGuid \a targetGuid parameter originally passed to UDPProxyClient::RequestForwarding
	/// \param[out] proxyClient The plugin that is calling this callback
	virtual void OnForwardingInProgress(const char *proxyIPAddress, unsigned short proxyPort, SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddress, RakNetGUID targetGuid, RakNet::UDPProxyClient *proxyClientPlugin)=0;
};
class RAK_DLL_EXPORT UDPProxyClient : public PluginInterface2
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(UDPProxyClient)

	UDPProxyClient();
	~UDPProxyClient();

	/// Receives the results of calling RequestForwarding()
	/// Set before calling RequestForwarding or you won‘t know what happened
	/// \param[in] resultHandler 
	void SetResultHandler(UDPProxyClientResultHandler *rh);

	/// Sends a request to proxyCoordinator to find a server and have that server setup UDPForwarder::StartForwarding() on our address to \a targetAddressAsSeenFromCoordinator
	/// The forwarded datagrams can be from any UDP source, not just RakNet
	/// \pre Must be connected to \a proxyCoordinator
	/// \pre Systems running UDPProxyServer must be connected to \a proxyCoordinator and logged in via UDPProxyCoordinator::LoginServer() or UDPProxyServer::LoginToCoordinator()
	/// \note May still fail, if all proxy servers have no open connections.
	/// \note RakNet‘s protocol will ensure a message is sent at least every 5 seconds, so if routing RakNet messages, it is a reasonable value for timeoutOnNoDataMS, plus an extra few seconds for latency.
	/// \param[in] proxyCoordinator System we are connected to that is running the UDPProxyCoordinator plugin
	/// \param[in] sourceAddress External IP address of the system we want to forward messages from. This does not have to be our own system. To specify our own system, you can pass UNASSIGNED_SYSTEM_ADDRESS which the coordinator will treat as our external IP address.
	/// \param[in] targetAddressAsSeenFromCoordinator External IP address of the system we want to forward messages to. If this system is connected to UDPProxyCoordinator at this address using RakNet, that system will ping the server and thus open the router for incoming communication. In any other case, you are responsible for doing your own network communication to have that system ping the server. See also targetGuid in the other version of RequestForwarding(), to avoid the need to know the IP address to the coordinator of the destination.
	/// \param[in] timeoutOnNoData If no data is sent by the forwarded systems, how long before removing the forward entry from UDPForwarder? UDP_FORWARDER_MAXIMUM_TIMEOUT is the maximum value. Recommended 10 seconds.
	/// \param[in] serverSelectionBitstream If you want to send data to UDPProxyCoordinator::GetBestServer(), write it here
	/// \return true if the request was sent, false if we are not connected to proxyCoordinator
	bool RequestForwarding(SystemAddress proxyCoordinator, SystemAddress sourceAddress, SystemAddress targetAddressAsSeenFromCoordinator, RakNet::TimeMS timeoutOnNoDataMS, RakNet::BitStream *serverSelectionBitstream=0);

	/// Same as above, but specify the target with a GUID, in case you don‘t know what its address is to the coordinator
	/// If requesting forwarding to a RakNet enabled system, then it is easier to use targetGuid instead of targetAddressAsSeenFromCoordinator
	bool RequestForwarding(SystemAddress proxyCoordinator, SystemAddress sourceAddress, RakNetGUID targetGuid, RakNet::TimeMS timeoutOnNoDataMS, RakNet::BitStream *serverSelectionBitstream=0);

	/// \internal
	virtual void Update(void);
	virtual PluginReceiveResult OnReceive(Packet *packet);
	virtual void OnRakPeerShutdown(void);
	
	struct ServerWithPing
	{
		unsigned short ping;
		SystemAddress serverAddress;
	};
	struct SenderAndTargetAddress
	{
		SystemAddress senderClientAddress;
		SystemAddress targetClientAddress;
	};
	struct PingServerGroup
	{
		SenderAndTargetAddress sata;
		RakNet::TimeMS startPingTime;
		SystemAddress coordinatorAddressForPings;
		//DataStructures::Multilist<ML_UNORDERED_LIST, ServerWithPing> serversToPing;
		DataStructures::List<ServerWithPing> serversToPing;
		bool AreAllServersPinged(void) const;
		void SendPingedServersToCoordinator(RakPeerInterface *rakPeerInterface);
	};
	//DataStructures::Multilist<ML_UNORDERED_LIST, PingServerGroup*> pingServerGroups;
	DataStructures::List<PingServerGroup*> pingServerGroups;
protected:

	void OnPingServers(Packet *packet);
	void Clear(void);
	UDPProxyClientResultHandler *resultHandler;
};
服务端:

struct UDPProxyServerResultHandler //服务端返回处理
{
	UDPProxyServerResultHandler() {}
	virtual ~UDPProxyServerResultHandler() {}

	/// Called when our login succeeds
	/// \param[out] usedPassword The password we passed to UDPProxyServer::LoginToCoordinator()
	/// \param[out] proxyServer The plugin calling this callback
	virtual void OnLoginSuccess(RakNet::RakString usedPassword, RakNet::UDPProxyServer *proxyServerPlugin)=0;

	/// We are already logged in.
	/// This login failed, but the system is operational as if it succeeded
	/// \param[out] usedPassword The password we passed to UDPProxyServer::LoginToCoordinator()
	/// \param[out] proxyServer The plugin calling this callback
	virtual void OnAlreadyLoggedIn(RakNet::RakString usedPassword, RakNet::UDPProxyServer *proxyServerPlugin)=0;

	/// The coordinator operator forgot to call UDPProxyCoordinator::SetRemoteLoginPassword()
	/// \param[out] usedPassword The password we passed to UDPProxyServer::LoginToCoordinator()
	/// \param[out] proxyServer The plugin calling this callback
	virtual void OnNoPasswordSet(RakNet::RakString usedPassword, RakNet::UDPProxyServer *proxyServerPlugin)=0;

	/// The coordinator operator set a different password in UDPProxyCoordinator::SetRemoteLoginPassword() than what we passed
	/// \param[out] usedPassword The password we passed to UDPProxyServer::LoginToCoordinator()
	/// \param[out] proxyServer The plugin calling this callback
	virtual void OnWrongPassword(RakNet::RakString usedPassword, RakNet::UDPProxyServer *proxyServerPlugin)=0;
};
class RAK_DLL_EXPORT UDPProxyServer : public PluginInterface2
{
public:
	// GetInstance() and DestroyInstance(instance*)
	STATIC_FACTORY_DECLARATIONS(UDPProxyServer)

	UDPProxyServer();
	~UDPProxyServer();

	/// Sets the socket family to use, either IPV4 or IPV6
	/// \param[in] socketFamily For IPV4, use AF_INET (default). For IPV6, use AF_INET6. To autoselect, use AF_UNSPEC.
	void SetSocketFamily(unsigned short _socketFamily);

	/// Receives the results of calling LoginToCoordinator()
	/// Set before calling LoginToCoordinator or you won‘t know what happened
	/// \param[in] resultHandler 
	void SetResultHandler(UDPProxyServerResultHandler *rh);

	/// Before the coordinator will register the UDPProxyServer, you must login
	/// \pre Must be connected to the coordinator
	/// \pre Coordinator must have set a password with UDPProxyCoordinator::SetRemoteLoginPassword()
	/// \returns false if already logged in, or logging in. Returns true otherwise
	bool LoginToCoordinator(RakNet::RakString password, SystemAddress coordinatorAddress);

	/// \brief The server IP reported to the client is the IP address from the server to the coordinator.
	/// If the server and coordinator are on the same LAN, you need to call SetServerPublicIP() to tell the client what address to connect to
	/// \param[in] ip IP address to report in UDPProxyClientResultHandler::OnForwardingSuccess() and UDPProxyClientResultHandler::OnForwardingNotification() as proxyIPAddress
	void SetServerPublicIP(RakString ip);

	/// Operative class that performs the forwarding
	/// Exposed so you can call UDPForwarder::SetMaxForwardEntries() if you want to change away from the default
	/// UDPForwarder::Startup(), UDPForwarder::Shutdown(), and UDPForwarder::Update() are called automatically by the plugin
	UDPForwarder udpForwarder;

	virtual void OnAttach(void);
	virtual void OnDetach(void);

	/// \internal
	virtual void Update(void);
	virtual PluginReceiveResult OnReceive(Packet *packet);
	virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
	virtual void OnRakPeerStartup(void);
	virtual void OnRakPeerShutdown(void);

protected:
	void OnForwardingRequestFromCoordinatorToServer(Packet *packet);

	DataStructures::OrderedList<SystemAddress, SystemAddress> loggingInCoordinators;
	DataStructures::OrderedList<SystemAddress, SystemAddress> loggedInCoordinators;

	UDPProxyServerResultHandler *resultHandler;
	unsigned short socketFamily;
	RakString serverPublicIp;
};

31、穿透

有服务端和客户端之分

客户端定义结构如下:

struct RAK_DLL_EXPORT PunchthroughConfiguration
{
	/// internal: (15 ms * 2 tries + 30 wait) * 5 ports * 8 players = 2.4 seconds
	/// external: (50 ms * 8 sends + 200 wait) * 2 port * 8 players = 9.6 seconds
	/// Total: 8 seconds
	PunchthroughConfiguration() {
		TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL=15;
		TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL=50;
		UDP_SENDS_PER_PORT_INTERNAL=2;
		UDP_SENDS_PER_PORT_EXTERNAL=8;
		INTERNAL_IP_WAIT_AFTER_ATTEMPTS=30;
		MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK=5; /// set to 0 to not do lan connects
		MAX_PREDICTIVE_PORT_RANGE=2;
		EXTERNAL_IP_WAIT_BETWEEN_PORTS=200;
		EXTERNAL_IP_WAIT_AFTER_FIRST_TTL=100;
		EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS=EXTERNAL_IP_WAIT_BETWEEN_PORTS;
		retryOnFailure=false;
	}

	/// How much time between each UDP send
	RakNet::Time TIME_BETWEEN_PUNCH_ATTEMPTS_INTERNAL;
	RakNet::Time TIME_BETWEEN_PUNCH_ATTEMPTS_EXTERNAL;

	/// How many tries for one port before giving up and going to the next port
	int UDP_SENDS_PER_PORT_INTERNAL;
	int UDP_SENDS_PER_PORT_EXTERNAL;

	/// After giving up on one internal port, how long to wait before trying the next port
	int INTERNAL_IP_WAIT_AFTER_ATTEMPTS;

	/// How many external ports to try past the last known starting port
	int MAX_PREDICTIVE_PORT_RANGE;

	/// After sending TTL, how long to wait until first punch attempt
	int EXTERNAL_IP_WAIT_AFTER_FIRST_TTL;

	/// After giving up on one external  port, how long to wait before trying the next port
	int EXTERNAL_IP_WAIT_BETWEEN_PORTS;

	/// After trying all external ports, how long to wait before returning ID_NAT_PUNCHTHROUGH_FAILED
	int EXTERNAL_IP_WAIT_AFTER_ALL_ATTEMPTS;

	/// Maximum number of internal IP address to try to connect to.
	/// Cannot be greater than MAXIMUM_NUMBER_OF_INTERNAL_IDS
	/// Should be high enough to try all internal IP addresses on the majority of computers
	int MAXIMUM_NUMBER_OF_INTERNAL_IDS_TO_CHECK;

	/// If the first punchthrough attempt fails, try again
	/// This sometimes works because the remote router was looking for an incoming message on a higher numbered port before responding to a lower numbered port from the other system
	bool retryOnFailure;
};

/// \ingroup NAT_PUNCHTHROUGH_GROUP
struct RAK_DLL_EXPORT NatPunchthroughDebugInterface
{
	NatPunchthroughDebugInterface() {}
	virtual ~NatPunchthroughDebugInterface() {}
	virtual void OnClientMessage(const char *msg)=0;
};

/// \ingroup NAT_PUNCHTHROUGH_GROUP
struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_Printf : public NatPunchthroughDebugInterface
{
	virtual void OnClientMessage(const char *msg);
};

#if _RAKNET_SUPPORT_PacketLogger==1
/// \ingroup NAT_PUNCHTHROUGH_GROUP
struct RAK_DLL_EXPORT NatPunchthroughDebugInterface_PacketLogger : public NatPunchthroughDebugInterface
{
	// Set to non-zero to write to the packetlogger!
	PacketLogger *pl;

	NatPunchthroughDebugInterface_PacketLogger() {pl=0;}
	~NatPunchthroughDebugInterface_PacketLogger() {}
	virtual void OnClientMessage(const char *msg);
};
#endif
客户端实现类:

class RAK_DLL_EXPORT NatPunchthroughClient : public PluginInterface2
服务器定义结构如下:

struct RAK_DLL_EXPORT NatPunchthroughServerDebugInterface
{
	NatPunchthroughServerDebugInterface() {}
	virtual ~NatPunchthroughServerDebugInterface() {}
	virtual void OnServerMessage(const char *msg)=0;
};

/// \ingroup NAT_PUNCHTHROUGH_GROUP
struct RAK_DLL_EXPORT NatPunchthroughServerDebugInterface_Printf : public NatPunchthroughServerDebugInterface
{
	virtual void OnServerMessage(const char *msg);
};

#if _RAKNET_SUPPORT_PacketLogger==1
/// \ingroup NAT_PUNCHTHROUGH_GROUP
struct RAK_DLL_EXPORT NatPunchthroughServerDebugInterface_PacketLogger : public NatPunchthroughServerDebugInterface
{
	// Set to non-zero to write to the packetlogger!
	PacketLogger *pl;

	NatPunchthroughServerDebugInterface_PacketLogger() {pl=0;}
	~NatPunchthroughServerDebugInterface_PacketLogger() {}
	virtual void OnServerMessage(const char *msg);
};
#endif
服务器实现类:

class RAK_DLL_EXPORT NatPunchthroughServer : public PluginInterface2
{
public:

	STATIC_FACTORY_DECLARATIONS(NatPunchthroughServer)

	// Constructor
	NatPunchthroughServer();

	// Destructor
	virtual ~NatPunchthroughServer();

	/// Sets a callback to be called with debug messages
	/// \param[in] i Pointer to an interface. The pointer is stored, so don‘t delete it while in progress. Pass 0 to clear.
	void SetDebugInterface(NatPunchthroughServerDebugInterface *i);

	/// \internal For plugin handling
	virtual void Update(void);

	/// \internal For plugin handling
	virtual PluginReceiveResult OnReceive(Packet *packet);

	/// \internal For plugin handling
	virtual void OnClosedConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, PI2_LostConnectionReason lostConnectionReason );
	virtual void OnNewConnection(const SystemAddress &systemAddress, RakNetGUID rakNetGUID, bool isIncoming);

	// Each connected user has a ready state. Ready means ready for nat punchthrough.
	struct User;
	struct ConnectionAttempt
	{
		ConnectionAttempt() {sender=0; recipient=0; startTime=0; attemptPhase=NAT_ATTEMPT_PHASE_NOT_STARTED;}
		User *sender, *recipient;
		uint16_t sessionId;
		RakNet::Time startTime;
		enum
		{
			NAT_ATTEMPT_PHASE_NOT_STARTED,
			NAT_ATTEMPT_PHASE_GETTING_RECENT_PORTS,
		} attemptPhase;
	};
	struct User
	{
		RakNetGUID guid;
		SystemAddress systemAddress;
		unsigned short mostRecentPort;
		bool isReady;
		DataStructures::OrderedList<RakNetGUID,RakNetGUID> groupPunchthroughRequests;

		DataStructures::List<ConnectionAttempt *> connectionAttempts;
		bool HasConnectionAttemptToUser(User *user);
		void DerefConnectionAttempt(ConnectionAttempt *ca);
		void DeleteConnectionAttempt(ConnectionAttempt *ca);
		void LogConnectionAttempts(RakNet::RakString &rs);
	};
	RakNet::Time lastUpdate;
	static int NatPunchthroughUserComp( const RakNetGUID &key, User * const &data );
protected:
	void OnNATPunchthroughRequest(Packet *packet);
	DataStructures::OrderedList<RakNetGUID, User*, NatPunchthroughServer::NatPunchthroughUserComp> users;

	void OnGetMostRecentPort(Packet *packet);
	void OnClientReady(Packet *packet);

	void SendTimestamps(void);
	void StartPendingPunchthrough(void);
	void StartPunchthroughForUser(User*user);
	uint16_t sessionId;
	NatPunchthroughServerDebugInterface *natPunchthroughServerDebugInterface;

	SystemAddress boundAddresses[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
	unsigned char boundAddressCount;
};

32、动态域名

enum DynDnsResultCode //返回结果
{
	// ----- Success -----
	RC_SUCCESS,
	RC_DNS_ALREADY_SET, // RakNet detects no action is needed

	// ----- Ignorable failure (treat same as success) -----
	RC_NO_CHANGE, // DynDNS detects no action is needed (treated as abuse though)

	// ----- User error -----
	RC_NOT_DONATOR, // You have to pay to do this
	RC_NO_HOST, // This host does not exist at all
	RC_BAD_AUTH, // You set the wrong password
	RC_NOT_YOURS, // This is not your host

	// ----- Permanent failure -----
	RC_ABUSE, // Your host has been blocked, too many failures disable your account
	RC_TCP_FAILED_TO_START, // TCP port already in use
	RC_TCP_DID_NOT_CONNECT, // DynDNS down?
	RC_UNKNOWN_RESULT, // DynDNS returned a result code that was not documented as of 12/4/2010 on http://www.dyndns.com/developers/specs/flow.pdf
	RC_PARSING_FAILURE, // Can‘t read the result returned, format change?
	RC_CONNECTION_LOST_WITHOUT_RESPONSE, // Lost the connection to DynDNS while communicating
	RC_BAD_AGENT, // ???
	RC_BAD_SYS, // ???
	RC_DNS_ERROR, // ???
	RC_NOT_FQDN, // ???
	RC_NUM_HOST, // ???
	RC_911, // ???
	RC_DYNDNS_TIMEOUT // DynDNS did not respond
};
实现类:

class RAK_DLL_EXPORT DynDNS
{
public:
	DynDNS();
	~DynDNS();

	// Pass 0 for newIPAddress to autodetect whatever you are uploading from
	// usernameAndPassword should be in the format username:password
	void UpdateHostIPAsynch(const char *dnsHost, const char *newIPAddress, const char *usernameAndPassword );
	void Update(void);

	// Output
	bool IsRunning(void) const {return connectPhase!=CP_IDLE;}
	bool IsCompleted(void) const {return connectPhase==CP_IDLE;}
	RakNet::DynDnsResultCode GetCompletedResultCode(void) {return result;}
	const char *GetCompletedDescription(void) const {return resultDescription;}
	bool WasResultSuccessful(void) const {return result==RC_SUCCESS || result==RC_DNS_ALREADY_SET || result==RC_NO_CHANGE;}
	char *GetMyPublicIP(void) const {return (char*) myIPStr;} // We get our public IP as part of the process. This is valid once completed

protected:
	void Stop(void);
	void SetCompleted(RakNet::DynDnsResultCode _result, const char *_resultDescription) {Stop(); result=_result; resultDescription=_resultDescription;}

	enum ConnectPhase
	{
		CP_CONNECTING_TO_CHECKIP,
		CP_WAITING_FOR_CHECKIP_RESPONSE,
		CP_CONNECTING_TO_DYNDNS,
		CP_WAITING_FOR_DYNDNS_RESPONSE,
		CP_IDLE
	};

	TCPInterface *tcp;
	RakNet::RakString getString;
	SystemAddress serverAddress;
	ConnectPhase connectPhase;
	RakNet::RakString host;
	RakNet::Time phaseTimeout;
	SystemAddress checkIpAddress;
	const char *resultDescription;
	RakNet::DynDnsResultCode result;
	char myIPStr[32];
};

33、权重图

权重图类是一个模版类,如下:

	template <class node_type, class weight_type, bool allow_unlinkedNodes>
	class RAK_DLL_EXPORT WeightedGraph //权重图
	{
	public:
		static void IMPLEMENT_DEFAULT_COMPARISON(void) {DataStructures::defaultMapKeyComparison<node_type>(node_type(),node_type());}

		WeightedGraph();
		~WeightedGraph();
		WeightedGraph( const WeightedGraph& original_copy );
		WeightedGraph& operator= ( const WeightedGraph& original_copy );
		void AddNode(const node_type &node);
		void RemoveNode(const node_type &node);
		void AddConnection(const node_type &node1, const node_type &node2, weight_type weight);
		void RemoveConnection(const node_type &node1, const node_type &node2);
		bool HasConnection(const node_type &node1, const node_type &node2);
		void Print(void);
		void Clear(void);
		bool GetShortestPath(DataStructures::List<node_type> &path, node_type startNode, node_type endNode, weight_type INFINITE_WEIGHT);
		bool GetSpanningTree(DataStructures::Tree<node_type> &outTree, DataStructures::List<node_type> *inputNodes, node_type startNode, weight_type INFINITE_WEIGHT );
		unsigned GetNodeCount(void) const;
		unsigned GetConnectionCount(unsigned nodeIndex) const;
		void GetConnectionAtIndex(unsigned nodeIndex, unsigned connectionIndex, node_type &outNode, weight_type &outWeight) const;
		node_type GetNodeAtIndex(unsigned nodeIndex) const;

	protected:
		void ClearDijkstra(void);
		void GenerateDisjktraMatrix(node_type startNode, weight_type INFINITE_WEIGHT);

		DataStructures::Map<node_type, DataStructures::Map<node_type, weight_type> *> adjacencyLists;

		// All these variables are for path finding with Dijkstra
		// 08/23/06 Won‘t compile as a DLL inside this struct
	//	struct  
	//	{
			bool isValidPath;
			node_type rootNode;
			DataStructures::OrderedList<node_type, node_type> costMatrixIndices;
			weight_type *costMatrix;
			node_type *leastNodeArray;
	//	} dijkstra;

		struct NodeAndParent
		{
			DataStructures::Tree<node_type>*node;
			DataStructures::Tree<node_type>*parent;
		};
	};

34、实例类

class RAK_DLL_EXPORT RakPeer : public RakPeerInterface, public RNS2EventHandler
{
public:
	///Constructor
	RakPeer();
	///Destructor
	virtual ~RakPeer();
	//启动网络
	StartupResult Startup( unsigned int maxConnections, SocketDescriptor *socketDescriptors, unsigned socketDescriptorCount, int threadPriority=-99999 );

	/// 加密
	bool InitializeSecurity( const char *publicKey, const char *privateKey, bool bRequireClientKey = false );

	/// 关闭加密
	void DisableSecurity( void );

	/// 安全连接
	void AddToSecurityExceptionList(const char *ip);

	void RemoveFromSecurityExceptionList(const char *ip);

	bool IsInSecurityExceptionList(const char *ip);

	void SetMaximumIncomingConnections( unsigned short numberAllowed );

	unsigned int GetMaximumIncomingConnections( void ) const;

	unsigned short NumberOfConnections(void) const;

	void SetIncomingPassword( const char* passwordData, int passwordDataLength );

	void GetIncomingPassword( char* passwordData, int *passwordDataLength  );

	ConnectionAttemptResult Connect( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, PublicKey *publicKey=0, unsigned connectionSocketIndex=0, unsigned sendConnectionAttemptCount=6, unsigned timeBetweenSendConnectionAttemptsMS=1000, RakNet::TimeMS timeoutTime=0 );

	virtual ConnectionAttemptResult ConnectWithSocket(const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, RakNetSocket2* socket, PublicKey *publicKey=0, unsigned sendConnectionAttemptCount=6, unsigned timeBetweenSendConnectionAttemptsMS=1000, RakNet::TimeMS timeoutTime=0);

	//bool Console2LobbyConnect( void *networkServiceId, const char *passwordData, int passwordDataLength );*/	

	void Shutdown( unsigned int blockDuration, unsigned char orderingChannel=0, PacketPriority disconnectionNotificationPriority=LOW_PRIORITY );

	bool IsActive( void ) const;

	bool GetConnectionList( SystemAddress *remoteSystems, unsigned short *numberOfSystems ) const;

	virtual uint32_t GetNextSendReceipt(void);

	virtual uint32_t IncrementNextSendReceipt(void);

	uint32_t Send( const char *data, const int length, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 );

	void SendLoopback( const char *data, const int length );

	uint32_t Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 );

	uint32_t SendList( const char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 );

	Packet* Receive( void );

	void DeallocatePacket( Packet *packet );

	unsigned int GetMaximumNumberOfPeers( void ) const;

	void CloseConnection( const AddressOrGUID target, bool sendDisconnectionNotification, unsigned char orderingChannel=0, PacketPriority disconnectionNotificationPriority=LOW_PRIORITY );

	void CancelConnectionAttempt( const SystemAddress target );
	
	ConnectionState GetConnectionState(const AddressOrGUID systemIdentifier);

	int GetIndexFromSystemAddress( const SystemAddress systemAddress ) const;

	SystemAddress GetSystemAddressFromIndex( unsigned int index );

	RakNetGUID GetGUIDFromIndex( unsigned int index );

	void GetSystemList(DataStructures::List<SystemAddress> &addresses, DataStructures::List<RakNetGUID> &guids) const;

	void AddToBanList( const char *IP, RakNet::TimeMS milliseconds=0 );

	void RemoveFromBanList( const char *IP );

	void ClearBanList( void );

	bool IsBanned( const char *IP );

	void SetLimitIPConnectionFrequency(bool b);
	
	void Ping( const SystemAddress target );

	bool Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, unsigned connectionSocketIndex=0 );

	int GetAveragePing( const AddressOrGUID systemIdentifier );

	int GetLastPing( const AddressOrGUID systemIdentifier ) const;

	int GetLowestPing( const AddressOrGUID systemIdentifier ) const;

	void SetOccasionalPing( bool doPing );

	RakNet::Time GetClockDifferential( const AddressOrGUID systemIdentifier );
	
	void SetOfflinePingResponse( const char *data, const unsigned int length );

	void GetOfflinePingResponse( char **data, unsigned int *length );
	
	SystemAddress GetInternalID( const SystemAddress systemAddress=UNASSIGNED_SYSTEM_ADDRESS, const int index=0 ) const;

	void SetInternalID(SystemAddress systemAddress, int index=0);

	SystemAddress GetExternalID( const SystemAddress target ) const;

	const RakNetGUID GetMyGUID(void) const;

	SystemAddress GetMyBoundAddress(const int socketIndex=0);

	const RakNetGUID& GetGuidFromSystemAddress( const SystemAddress input ) const;

	SystemAddress GetSystemAddressFromGuid( const RakNetGUID input ) const;

	bool GetClientPublicKeyFromSystemAddress( const SystemAddress input, char *client_public_key ) const;

	void SetTimeoutTime( RakNet::TimeMS timeMS, const SystemAddress target );
	
	RakNet::TimeMS GetTimeoutTime( const SystemAddress target );

	int GetMTUSize( const SystemAddress target ) const;

	unsigned GetNumberOfAddresses( void );

	const char* GetLocalIP( unsigned int index );

	bool IsLocalIP( const char *ip );

	void AllowConnectionResponseIPMigration( bool allow );

	bool AdvertiseSystem( const char *host, unsigned short remotePort, const char *data, int dataLength, unsigned connectionSocketIndex=0 );

	void SetSplitMessageProgressInterval(int interval);

	int GetSplitMessageProgressInterval(void) const;

	void SetUnreliableTimeout(RakNet::TimeMS timeoutMS);

	void SendTTL( const char* host, unsigned short remotePort, int ttl, unsigned connectionSocketIndex=0 );

	void AttachPlugin( PluginInterface2 *plugin );

	void DetachPlugin( PluginInterface2 *messageHandler );

	void PushBackPacket( Packet *packet, bool pushAtHead );

	void ChangeSystemAddress(RakNetGUID guid, const SystemAddress &systemAddress);

	Packet* AllocatePacket(unsigned dataSize);

	virtual RakNetSocket2* GetSocket( const SystemAddress target );

	virtual void GetSockets( DataStructures::List<RakNetSocket2* > &sockets );
	virtual void ReleaseSockets( DataStructures::List<RakNetSocket2* > &sockets );

	virtual void WriteOutOfBandHeader(RakNet::BitStream *bitStream);

	virtual void SetUserUpdateThread(void (*_userUpdateThreadPtr)(RakPeerInterface *, void *), void *_userUpdateThreadData);

	virtual void SetIncomingDatagramEventHandler( bool (*_incomingDatagramEventHandler)(RNS2RecvStruct *) );

	virtual void ApplyNetworkSimulator( float packetloss, unsigned short minExtraPing, unsigned short extraPingVariance);

	virtual void SetPerConnectionOutgoingBandwidthLimit( unsigned maxBitsPerSecond );

	virtual bool IsNetworkSimulatorActive( void );

	RakNetStatistics * GetStatistics( const SystemAddress systemAddress, RakNetStatistics *rns=0 );
	
	bool GetStatistics( const unsigned int index, RakNetStatistics *rns );
	
	virtual void GetStatisticsList(DataStructures::List<SystemAddress> &addresses, DataStructures::List<RakNetGUID> &guids, DataStructures::List<RakNetStatistics> &statistics);

	virtual unsigned int GetReceiveBufferSize(void);

	bool RunUpdateCycle( BitStream &updateBitStream );

	bool SendOutOfBand(const char *host, unsigned short remotePort, const char *data, BitSize_t dataLength, unsigned connectionSocketIndex=0 );

	// static Packet *AllocPacket(unsigned dataSize, const char *file, unsigned int line);

	/// \internal
	/// \brief Holds the clock differences between systems, along with the ping
	struct PingAndClockDifferential
	{
		unsigned short pingTime;
		RakNet::Time clockDifferential;
	};

	/// \internal
	/// \brief All the information representing a connected system
	struct RemoteSystemStruct
	{
		bool isActive; // Is this structure in use?
		SystemAddress systemAddress;  /// Their external IP on the internet
		SystemAddress myExternalSystemAddress;  /// Your external IP on the internet, from their perspective
		SystemAddress theirInternalSystemAddress[MAXIMUM_NUMBER_OF_INTERNAL_IDS];  /// Their internal IP, behind the LAN
		ReliabilityLayer reliabilityLayer;  /// The reliability layer associated with this player
		bool weInitiatedTheConnection; /// True if we started this connection via Connect.  False if someone else connected to us.
		PingAndClockDifferential pingAndClockDifferential[ PING_TIMES_ARRAY_SIZE ];  /// last x ping times and calculated clock differentials with it
		RakNet::Time pingAndClockDifferentialWriteIndex;  /// The index we are writing into the pingAndClockDifferential circular buffer
		unsigned short lowestPing; ///The lowest ping value encountered
		RakNet::Time nextPingTime;  /// When to next ping this player
		RakNet::Time lastReliableSend; /// When did the last reliable send occur.  Reliable sends must occur at least once every timeoutTime/2 units to notice disconnects
		RakNet::Time connectionTime; /// connection time, if active.
//		int connectionSocketIndex; // index into connectionSockets to send back on.
		RakNetGUID guid;
		int MTUSize;
		// Reference counted socket to send back on
		RakNetSocket2* rakNetSocket;
		SystemIndex remoteSystemIndex;

#if LIBCAT_SECURITY==1
		// Cached answer used internally by RakPeer to prevent DoS attacks based on the connexion handshake
		char answer[cat::EasyHandshake::ANSWER_BYTES];

		// If the server has bRequireClientKey = true, then this is set to the validated public key of the connected client
		// Valid after connectMode reaches HANDLING_CONNECTION_REQUEST
		char client_public_key[cat::EasyHandshake::PUBLIC_KEY_BYTES];
#endif

		enum ConnectMode {NO_ACTION, DISCONNECT_ASAP, DISCONNECT_ASAP_SILENTLY, DISCONNECT_ON_NO_ACK, REQUESTED_CONNECTION, HANDLING_CONNECTION_REQUEST, UNVERIFIED_SENDER, CONNECTED} connectMode;
	};

	// DS_APR
	//void ProcessChromePacket(RakNetSocket2 *s, const char *buffer, int dataSize, const SystemAddress& recvFromAddress, RakNet::TimeUS timeRead);
	// /DS_APR
protected:

	friend RAK_THREAD_DECLARATION(UpdateNetworkLoop);
	//friend RAK_THREAD_DECLARATION(RecvFromLoop);
	friend RAK_THREAD_DECLARATION(UDTConnect);

	friend bool ProcessOfflineNetworkPacket( SystemAddress systemAddress, const char *data, const int length, RakPeer *rakPeer, RakNetSocket2* rakNetSocket, bool *isOfflineMessage, RakNet::TimeUS timeRead );
	friend void ProcessNetworkPacket( const SystemAddress systemAddress, const char *data, const int length, RakPeer *rakPeer, RakNet::TimeUS timeRead, BitStream &updateBitStream );
	friend void ProcessNetworkPacket( const SystemAddress systemAddress, const char *data, const int length, RakPeer *rakPeer, RakNetSocket2* rakNetSocket, RakNet::TimeUS timeRead, BitStream &updateBitStream );

	int GetIndexFromSystemAddress( const SystemAddress systemAddress, bool calledFromNetworkThread ) const;
	int GetIndexFromGuid( const RakNetGUID guid );

	//void RemoveFromRequestedConnectionsList( const SystemAddress systemAddress );
	// Two versions needed because some buggy compilers strip the last parameter if unused, and crashes
	ConnectionAttemptResult SendConnectionRequest( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, PublicKey *publicKey, unsigned connectionSocketIndex, unsigned int extraData, unsigned sendConnectionAttemptCount, unsigned timeBetweenSendConnectionAttemptsMS, RakNet::TimeMS timeoutTime, RakNetSocket2* socket );
	ConnectionAttemptResult SendConnectionRequest( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, PublicKey *publicKey, unsigned connectionSocketIndex, unsigned int extraData, unsigned sendConnectionAttemptCount, unsigned timeBetweenSendConnectionAttemptsMS, RakNet::TimeMS timeoutTime );
	///Get the reliability layer associated with a systemAddress.  
	/// \param[in] systemAddress The player identifier 
	/// \return 0 if none
	RemoteSystemStruct *GetRemoteSystemFromSystemAddress( const SystemAddress systemAddress, bool calledFromNetworkThread, bool onlyActive ) const;
	RakPeer::RemoteSystemStruct *GetRemoteSystem( const AddressOrGUID systemIdentifier, bool calledFromNetworkThread, bool onlyActive ) const;
	void ValidateRemoteSystemLookup(void) const;
	RemoteSystemStruct *GetRemoteSystemFromGUID( const RakNetGUID guid, bool onlyActive ) const;
	///Parse out a connection request packet
	void ParseConnectionRequestPacket( RakPeer::RemoteSystemStruct *remoteSystem, const SystemAddress &systemAddress, const char *data, int byteSize);
	void OnConnectionRequest( RakPeer::RemoteSystemStruct *remoteSystem, RakNet::Time incomingTimestamp );
	///Send a reliable disconnect packet to this player and disconnect them when it is delivered
	void NotifyAndFlagForShutdown( const SystemAddress systemAddress, bool performImmediate, unsigned char orderingChannel, PacketPriority disconnectionNotificationPriority );
	///Returns how many remote systems initiated a connection to us
	unsigned int GetNumberOfRemoteInitiatedConnections( void ) const;
	///	\brief Get a free remote system from the list and assign our systemAddress to it.
	/// \note Should only be called from the update thread - not the user thread.
	/// \param[in] systemAddress	systemAddress to be assigned
	/// \param[in] connectionMode	connection mode of the RemoteSystem.
	/// \param[in] rakNetSocket 
	/// \param[in] thisIPConnectedRecently	Is this IP connected recently? set to False;
	/// \param[in] bindingAddress	Address to be binded with the remote system
	/// \param[in] incomingMTU	MTU for the remote system
	RemoteSystemStruct * AssignSystemAddressToRemoteSystemList( const SystemAddress systemAddress, RemoteSystemStruct::ConnectMode connectionMode, RakNetSocket2* incomingRakNetSocket, bool *thisIPConnectedRecently, SystemAddress bindingAddress, int incomingMTU, RakNetGUID guid, bool useSecurity );
	///	\brief Adjust the timestamp of the incoming packet to be relative to this system.
	/// \param[in] data	Data in the incoming packet.
	/// \param[in] systemAddress Sender of the incoming packet.
	void ShiftIncomingTimestamp( unsigned char *data, const SystemAddress &systemAddress ) const;
	/// Get the most accurate clock differential for a certain player.
	/// \param[in] systemAddress The player with whose clock the time difference is calculated.
	/// \returns The clock differential for a certain player.
	RakNet::Time GetBestClockDifferential( const SystemAddress systemAddress ) const;

	bool IsLoopbackAddress(const AddressOrGUID &systemIdentifier, bool matchPort) const;
	SystemAddress GetLoopbackAddress(void) const;

	///Set this to true to terminate the Peer thread execution 
	volatile bool endThreads;
	///true if the peer thread is active. 
	volatile bool isMainLoopThreadActive;
	
	// RakNet::LocklessUint32_t isRecvFromLoopThreadActive;


	bool occasionalPing;  /// Do we occasionally ping the other systems?*/
	///Store the maximum number of peers allowed to connect
	unsigned int maximumNumberOfPeers;
	//05/02/06 Just using maximumNumberOfPeers instead
	///Store the maximum number of peers able to connect, including reserved connection slots for pings, etc.
	//unsigned short remoteSystemListSize;
	///Store the maximum incoming connection allowed 
	unsigned int maximumIncomingConnections;
	RakNet::BitStream offlinePingResponse;
	///Local Player ID
	// SystemAddress mySystemAddress[MAXIMUM_NUMBER_OF_INTERNAL_IDS];
	char incomingPassword[256];
	unsigned char incomingPasswordLength;

	/// This is an array of pointers to RemoteSystemStruct
	/// This allows us to preallocate the list when starting, so we don‘t have to allocate or delete at runtime.
	/// Another benefit is that is lets us add and remove active players simply by setting systemAddress
	/// and moving elements in the list by copying pointers variables without affecting running threads, even if they are in the reliability layer
	RemoteSystemStruct* remoteSystemList;
	/// activeSystemList holds a list of pointers and is preallocated to be the same size as remoteSystemList. It is updated only by the network thread, but read by both threads
	/// When the isActive member of RemoteSystemStruct is set to true or false, that system is added to this list of pointers
	/// Threadsafe because RemoteSystemStruct is preallocated, and the list is only added to, not removed from
	RemoteSystemStruct** activeSystemList;
	unsigned int activeSystemListSize;

	// Use a hash, with binaryAddress plus port mod length as the index
	RemoteSystemIndex **remoteSystemLookup;
	unsigned int RemoteSystemLookupHashIndex(const SystemAddress &sa) const;
	void ReferenceRemoteSystem(const SystemAddress &sa, unsigned int remoteSystemListIndex);
	void DereferenceRemoteSystem(const SystemAddress &sa);
	RemoteSystemStruct* GetRemoteSystem(const SystemAddress &sa) const;
	unsigned int GetRemoteSystemIndex(const SystemAddress &sa) const;
	void ClearRemoteSystemLookup(void);
	DataStructures::MemoryPool<RemoteSystemIndex> remoteSystemIndexPool;

	void AddToActiveSystemList(unsigned int remoteSystemListIndex);
	void RemoveFromActiveSystemList(const SystemAddress &sa);

//	unsigned int LookupIndexUsingHashIndex(const SystemAddress &sa) const;
//	unsigned int RemoteSystemListIndexUsingHashIndex(const SystemAddress &sa) const;
//	unsigned int FirstFreeRemoteSystemLookupIndex(const SystemAddress &sa) const;
	
	enum
	{
		// Only put these mutexes in user thread functions!
		requestedConnectionList_Mutex,
		offlinePingResponse_Mutex,
		NUMBER_OF_RAKPEER_MUTEXES
	};
	SimpleMutex rakPeerMutexes[ NUMBER_OF_RAKPEER_MUTEXES ];
	///RunUpdateCycle is not thread safe but we don‘t need to mutex calls. Just skip calls if it is running already

	bool updateCycleIsRunning;
	///The list of people we have tried to connect to recently
	//DataStructures::Queue<RequestedConnectionStruct*> requestedConnectionsList;
	///Data that both the client and the server needs
	unsigned int bytesSentPerSecond, bytesReceivedPerSecond;
	// bool isSocketLayerBlocking;
	// bool continualPing,isRecvfromThreadActive,isMainLoopThreadActive, endThreads, isSocketLayerBlocking;
	unsigned int validationInteger;
	SimpleMutex incomingQueueMutex, banListMutex; //,synchronizedMemoryQueueMutex, automaticVariableSynchronizationMutex;
	//DataStructures::Queue<Packet *> incomingpacketSingleProducerConsumer; //, synchronizedMemorypacketSingleProducerConsumer;
	// BitStream enumerationData;

	struct BanStruct
	{
		char *IP;
		RakNet::TimeMS timeout; // 0 for none
	};

	struct RequestedConnectionStruct
	{
		SystemAddress systemAddress;
		RakNet::Time nextRequestTime;
		unsigned char requestsMade;
		char *data;
		unsigned short dataLength;
		char outgoingPassword[256];
		unsigned char outgoingPasswordLength;
		unsigned socketIndex;
		unsigned int extraData;
		unsigned sendConnectionAttemptCount;
		unsigned timeBetweenSendConnectionAttemptsMS;
		RakNet::TimeMS timeoutTime;
		PublicKeyMode publicKeyMode;
		RakNetSocket2* socket;
		enum {CONNECT=1, /*PING=2, PING_OPEN_CONNECTIONS=4,*/ /*ADVERTISE_SYSTEM=2*/} actionToTake;

#if LIBCAT_SECURITY==1
		char handshakeChallenge[cat::EasyHandshake::CHALLENGE_BYTES];
		cat::ClientEasyHandshake *client_handshake;
		char remote_public_key[cat::EasyHandshake::PUBLIC_KEY_BYTES];
//		char remote_challenge[cat::EasyHandshake::CHALLENGE_BYTES];
	//	char random[16];
#endif
	};
#if LIBCAT_SECURITY==1
	bool GenerateConnectionRequestChallenge(RequestedConnectionStruct *rcs,PublicKey *publicKey);
#endif

	//DataStructures::List<DataStructures::List<MemoryBlock>* > automaticVariableSynchronizationList;
	DataStructures::List<BanStruct*> banList;
	// Threadsafe, and not thread safe
	DataStructures::List<PluginInterface2*> pluginListTS, pluginListNTS;

	DataStructures::Queue<RequestedConnectionStruct*> requestedConnectionQueue;
	SimpleMutex requestedConnectionQueueMutex;

	// void RunMutexedUpdateCycle(void);
	struct BufferedCommandStruct
	{
		BitSize_t numberOfBitsToSend;
		PacketPriority priority;
		PacketReliability reliability;
		char orderingChannel;
		AddressOrGUID systemIdentifier;
		bool broadcast;
		RemoteSystemStruct::ConnectMode connectionMode;
		NetworkID networkID;
		bool blockingCommand; // Only used for RPC
		char *data;
		bool haveRakNetCloseSocket;
		unsigned connectionSocketIndex;
		unsigned short remotePortRakNetWasStartedOn_PS3;
		unsigned int extraSocketOptions;
		RakNetSocket2* socket;
		unsigned short port;
		uint32_t receipt;
		enum {BCS_SEND, BCS_CLOSE_CONNECTION, BCS_GET_SOCKET, BCS_CHANGE_SYSTEM_ADDRESS,/* BCS_USE_USER_SOCKET, BCS_REBIND_SOCKET_ADDRESS, BCS_RPC, BCS_RPC_SHIFT,*/ BCS_DO_NOTHING} command;
	};

	// Single producer single consumer queue using a linked list
	//BufferedCommandStruct* bufferedCommandReadIndex, bufferedCommandWriteIndex;

	DataStructures::ThreadsafeAllocatingQueue<BufferedCommandStruct> bufferedCommands;
	// DataStructures::ThreadsafeAllocatingQueue<RNS2RecvStruct> bufferedPackets;

	DataStructures::Queue<RNS2RecvStruct*> bufferedPacketsFreePool;
	RakNet::SimpleMutex bufferedPacketsFreePoolMutex;
	DataStructures::Queue<RNS2RecvStruct*> bufferedPacketsQueue;
	RakNet::SimpleMutex bufferedPacketsQueueMutex;

	virtual void DeallocRNS2RecvStruct(RNS2RecvStruct *s, const char *file, unsigned int line);
	virtual RNS2RecvStruct *AllocRNS2RecvStruct(const char *file, unsigned int line);
	void SetupBufferedPackets(void);
	void PushBufferedPacket(RNS2RecvStruct * p);
	RNS2RecvStruct *PopBufferedPacket(void);

	struct SocketQueryOutput
	{
		SocketQueryOutput() {}
		~SocketQueryOutput() {}
		DataStructures::List<RakNetSocket2* > sockets;
	};

	DataStructures::ThreadsafeAllocatingQueue<SocketQueryOutput> socketQueryOutput;

	bool AllowIncomingConnections(void) const;

	void PingInternal( const SystemAddress target, bool performImmediate, PacketReliability reliability );
	// This stores the user send calls to be handled by the update thread.  This way we don‘t have thread contention over systemAddresss
	void CloseConnectionInternal( const AddressOrGUID& systemIdentifier, bool sendDisconnectionNotification, bool performImmediate, unsigned char orderingChannel, PacketPriority disconnectionNotificationPriority );
	void SendBuffered( const char *data, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, RemoteSystemStruct::ConnectMode connectionMode, uint32_t receipt );
	void SendBufferedList( const char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, RemoteSystemStruct::ConnectMode connectionMode, uint32_t receipt );
	bool SendImmediate( char *data, BitSize_t numberOfBitsToSend, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, bool useCallerDataAllocation, RakNet::TimeUS currentTime, uint32_t receipt );
	//bool HandleBufferedRPC(BufferedCommandStruct *bcs, RakNet::TimeMS time);
	void ClearBufferedCommands(void);
	void ClearBufferedPackets(void);
	void ClearSocketQueryOutput(void);
	void ClearRequestedConnectionList(void);
	void AddPacketToProducer(RakNet::Packet *p);
	unsigned int GenerateSeedFromGuid(void);
	RakNet::Time GetClockDifferentialInt(RemoteSystemStruct *remoteSystem) const;
	SimpleMutex securityExceptionMutex;

	//DataStructures::AVLBalancedBinarySearchTree<RPCNode> rpcTree;
	int defaultMTUSize;
	bool trackFrequencyTable;

	// Smart pointer so I can return the object to the user
	DataStructures::List<RakNetSocket2* > socketList;
	void DerefAllSockets(void);
	unsigned int GetRakNetSocketFromUserConnectionSocketIndex(unsigned int userIndex) const;
	// Used for RPC replies
	RakNet::BitStream *replyFromTargetBS;
	SystemAddress replyFromTargetPlayer;
	bool replyFromTargetBroadcast;

	RakNet::TimeMS defaultTimeoutTime;

	// Generate and store a unique GUID
	void GenerateGUID(void);
	unsigned int GetSystemIndexFromGuid( const RakNetGUID input ) const;
	RakNetGUID myGuid;

	unsigned maxOutgoingBPS;

	// Nobody would use the internet simulator in a final build.
#ifdef _DEBUG
	double _packetloss;
	unsigned short _minExtraPing, _extraPingVariance;
#endif
    
	///How long it has been since things were updated by a call to receiveUpdate thread uses this to determine how long to sleep for
	//unsigned int lastUserUpdateCycle;
	/// True to allow connection accepted packets from anyone.  False to only allow these packets from servers we requested a connection to.
	bool allowConnectionResponseIPMigration;

	SystemAddress firstExternalID;
	int splitMessageProgressInterval;
	RakNet::TimeMS unreliableTimeout;

	bool (*incomingDatagramEventHandler)(RNS2RecvStruct *);

	// Systems in this list will not go through the secure connection process, even when secure connections are turned on. Wildcards are accepted.
	DataStructures::List<RakNet::RakString> securityExceptionList;

	SystemAddress ipList[ MAXIMUM_NUMBER_OF_INTERNAL_IDS ];

	bool allowInternalRouting;

	void (*userUpdateThreadPtr)(RakPeerInterface *, void *);
	void *userUpdateThreadData;


	SignaledEvent quitAndDataEvents;
	bool limitConnectionFrequencyFromTheSameIP;

	SimpleMutex packetAllocationPoolMutex;
	DataStructures::MemoryPool<Packet> packetAllocationPool;

	SimpleMutex packetReturnMutex;
	DataStructures::Queue<Packet*> packetReturnQueue;
	Packet *AllocPacket(unsigned dataSize, const char *file, unsigned int line);
	Packet *AllocPacket(unsigned dataSize, unsigned char *data, const char *file, unsigned int line);

	/// This is used to return a number to the user when they call Send identifying the message
	/// This number will be returned back with ID_SND_RECEIPT_ACKED or ID_SND_RECEIPT_LOSS and is only returned
	/// with the reliability types that contain RECEIPT in the name
	SimpleMutex sendReceiptSerialMutex;
	uint32_t sendReceiptSerial;
	void ResetSendReceipt(void);
	void OnConnectedPong(RakNet::Time sendPingTime, RakNet::Time sendPongTime, RemoteSystemStruct *remoteSystem);
	void CallPluginCallbacks(DataStructures::List<PluginInterface2*> &pluginList, Packet *packet);

#if LIBCAT_SECURITY==1
	// Encryption and security
	bool _using_security, _require_client_public_key;
	char my_public_key[cat::EasyHandshake::PUBLIC_KEY_BYTES];
	cat::ServerEasyHandshake *_server_handshake;
	cat::CookieJar *_cookie_jar;
	bool InitializeClientSecurity(RequestedConnectionStruct *rcs, const char *public_key);
#endif

	virtual void OnRNS2Recv(RNS2RecvStruct *recvStruct);
	void FillIPList(void);
} 
// #if defined(SN_TARGET_PSP2)
// __attribute__((aligned(8)))
// #endif
;

} // namespace RakNet

36、实例操作接口

class RAK_DLL_EXPORT RakPeerInterface//网络接口
{
public:
	STATIC_FACTORY_DECLARATIONS(RakPeerInterface)

	virtual ~RakPeerInterface()	{}

	virtual StartupResult Startup( unsigned int maxConnections, SocketDescriptor *socketDescriptors, unsigned socketDescriptorCount, int threadPriority=-99999 )=0;

	virtual bool InitializeSecurity( const char *publicKey, const char *privateKey, bool bRequireClientKey = false )=0;

	virtual void DisableSecurity( void )=0;

	virtual void AddToSecurityExceptionList(const char *ip)=0;

	virtual void RemoveFromSecurityExceptionList(const char *ip)=0;

	virtual bool IsInSecurityExceptionList(const char *ip)=0;

	virtual void SetMaximumIncomingConnections( unsigned short numberAllowed )=0;

	virtual unsigned int GetMaximumIncomingConnections( void ) const=0;

	virtual unsigned short NumberOfConnections(void) const=0;

	virtual void SetIncomingPassword( const char* passwordData, int passwordDataLength )=0;

	virtual void GetIncomingPassword( char* passwordData, int *passwordDataLength  )=0;

	virtual ConnectionAttemptResult Connect( const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, PublicKey *publicKey=0, unsigned connectionSocketIndex=0, unsigned sendConnectionAttemptCount=12, unsigned timeBetweenSendConnectionAttemptsMS=500, RakNet::TimeMS timeoutTime=0 )=0;

	virtual ConnectionAttemptResult ConnectWithSocket(const char* host, unsigned short remotePort, const char *passwordData, int passwordDataLength, RakNetSocket2* socket, PublicKey *publicKey=0, unsigned sendConnectionAttemptCount=12, unsigned timeBetweenSendConnectionAttemptsMS=500, RakNet::TimeMS timeoutTime=0)=0;

	//virtual bool Console2LobbyConnect( void *networkServiceId, const char *passwordData, int passwordDataLength )=0;

	virtual void Shutdown( unsigned int blockDuration, unsigned char orderingChannel=0, PacketPriority disconnectionNotificationPriority=LOW_PRIORITY )=0;

	virtual bool IsActive( void ) const=0;

	virtual bool GetConnectionList( SystemAddress *remoteSystems, unsigned short *numberOfSystems ) const=0;

	virtual uint32_t GetNextSendReceipt(void)=0;

	virtual uint32_t IncrementNextSendReceipt(void)=0;

	virtual uint32_t Send( const char *data, const int length, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 )=0;

	virtual void SendLoopback( const char *data, const int length )=0;

	virtual uint32_t Send( const RakNet::BitStream * bitStream, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 )=0;

	virtual uint32_t SendList( const char **data, const int *lengths, const int numParameters, PacketPriority priority, PacketReliability reliability, char orderingChannel, const AddressOrGUID systemIdentifier, bool broadcast, uint32_t forceReceiptNumber=0 )=0;

	virtual Packet* Receive( void )=0;

	virtual void DeallocatePacket( Packet *packet )=0;

	virtual unsigned int GetMaximumNumberOfPeers( void ) const=0;

	virtual void CloseConnection( const AddressOrGUID target, bool sendDisconnectionNotification, unsigned char orderingChannel=0, PacketPriority disconnectionNotificationPriority=LOW_PRIORITY )=0;

	virtual ConnectionState GetConnectionState(const AddressOrGUID systemIdentifier)=0;

	virtual void CancelConnectionAttempt( const SystemAddress target )=0;

	virtual int GetIndexFromSystemAddress( const SystemAddress systemAddress ) const=0;

	virtual SystemAddress GetSystemAddressFromIndex( unsigned int index )=0;

	virtual RakNetGUID GetGUIDFromIndex( unsigned int index )=0;

	virtual void GetSystemList(DataStructures::List<SystemAddress> &addresses, DataStructures::List<RakNetGUID> &guids) const=0;

	virtual void AddToBanList( const char *IP, RakNet::TimeMS milliseconds=0 )=0;

	virtual void RemoveFromBanList( const char *IP )=0;

	virtual void ClearBanList( void )=0;

	virtual bool IsBanned( const char *IP )=0;

	virtual void SetLimitIPConnectionFrequency(bool b)=0;

	virtual void Ping( const SystemAddress target )=0;

	virtual bool Ping( const char* host, unsigned short remotePort, bool onlyReplyOnAcceptingConnections, unsigned connectionSocketIndex=0 )=0;

	virtual int GetAveragePing( const AddressOrGUID systemIdentifier )=0;

	virtual int GetLastPing( const AddressOrGUID systemIdentifier ) const=0;

	virtual int GetLowestPing( const AddressOrGUID systemIdentifier ) const=0;

	virtual void SetOccasionalPing( bool doPing )=0;

	virtual RakNet::Time GetClockDifferential( const AddressOrGUID systemIdentifier )=0;

	virtual void SetOfflinePingResponse( const char *data, const unsigned int length )=0;

	virtual void GetOfflinePingResponse( char **data, unsigned int *length )=0;

	virtual SystemAddress GetInternalID( const SystemAddress systemAddress=UNASSIGNED_SYSTEM_ADDRESS, const int index=0 ) const=0;

	virtual void SetInternalID(SystemAddress systemAddress, int index=0)=0;

	virtual SystemAddress GetExternalID( const SystemAddress target ) const=0;

	virtual const RakNetGUID GetMyGUID(void) const=0;

	virtual SystemAddress GetMyBoundAddress(const int socketIndex=0)=0;

	static uint64_t Get64BitUniqueRandomNumber(void);

	virtual const RakNetGUID& GetGuidFromSystemAddress( const SystemAddress input ) const=0;

	virtual SystemAddress GetSystemAddressFromGuid( const RakNetGUID input ) const=0;

	virtual bool GetClientPublicKeyFromSystemAddress( const SystemAddress input, char *client_public_key ) const=0;

	virtual void SetTimeoutTime( RakNet::TimeMS timeMS, const SystemAddress target )=0;

	virtual RakNet::TimeMS GetTimeoutTime( const SystemAddress target )=0;

	virtual int GetMTUSize( const SystemAddress target ) const=0;

	virtual unsigned GetNumberOfAddresses( void )=0;

	virtual const char* GetLocalIP( unsigned int index )=0;

	virtual bool IsLocalIP( const char *ip )=0;

	virtual void AllowConnectionResponseIPMigration( bool allow )=0;

	virtual bool AdvertiseSystem( const char *host, unsigned short remotePort, const char *data, int dataLength, unsigned connectionSocketIndex=0 )=0;

	virtual void SetSplitMessageProgressInterval(int interval)=0;

	virtual int GetSplitMessageProgressInterval(void) const=0;

	virtual void SetUnreliableTimeout(RakNet::TimeMS timeoutMS)=0;

	virtual void SendTTL( const char* host, unsigned short remotePort, int ttl, unsigned connectionSocketIndex=0 )=0;

	virtual void AttachPlugin( PluginInterface2 *plugin )=0;

	virtual void DetachPlugin( PluginInterface2 *messageHandler )=0;

	virtual void PushBackPacket( Packet *packet, bool pushAtHead )=0;

	virtual void ChangeSystemAddress(RakNetGUID guid, const SystemAddress &systemAddress)=0;

	virtual Packet* AllocatePacket(unsigned dataSize)=0;

	virtual RakNetSocket2* GetSocket( const SystemAddress target )=0;

	virtual void GetSockets( DataStructures::List<RakNetSocket2* > &sockets )=0;
	virtual void ReleaseSockets( DataStructures::List<RakNetSocket2* > &sockets )=0;

	virtual void WriteOutOfBandHeader(RakNet::BitStream *bitStream)=0;

	virtual void SetUserUpdateThread(void (*_userUpdateThreadPtr)(RakPeerInterface *, void *), void *_userUpdateThreadData)=0;

	virtual void SetIncomingDatagramEventHandler( bool (*_incomingDatagramEventHandler)(RNS2RecvStruct *) )=0;

	virtual void ApplyNetworkSimulator( float packetloss, unsigned short minExtraPing, unsigned short extraPingVariance)=0;

	virtual void SetPerConnectionOutgoingBandwidthLimit( unsigned maxBitsPerSecond )=0;

	virtual bool IsNetworkSimulatorActive( void )=0;

	virtual RakNetStatistics * GetStatistics( const SystemAddress systemAddress, RakNetStatistics *rns=0 )=0;
	
	virtual bool GetStatistics( const unsigned int index, RakNetStatistics *rns )=0;
	
	virtual void GetStatisticsList(DataStructures::List<SystemAddress> &addresses, DataStructures::List<RakNetGUID> &guids, DataStructures::List<RakNetStatistics> &statistics)=0;

	virtual unsigned int GetReceiveBufferSize(void)=0;

	virtual bool RunUpdateCycle( BitStream &updateBitStream )=0;

	virtual bool SendOutOfBand(const char *host, unsigned short remotePort, const char *data, BitSize_t dataLength, unsigned connectionSocketIndex=0 )=0;
}

总结

Raknet很强大,可强大的不是它的代码而是它的思想。

Android RakNet 系列之六 源码说明