1. 程式人生 > >[網路開發]RakNet翻譯文件(4)

[網路開發]RakNet翻譯文件(4)

抱歉這篇文章出現這麼遲。

當一個數據包出現在網路上的時候,例如收到了返回值不為零的資料,涉及了三個步驟來處理它。

1.確定這個資料包的型別,它通過如下程式碼被返回

unsigned char GetPacketIdentifier(Packet *p)
{
	if ((unsigned char)p->data[0] == ID_TIMESTAMP)
		return (unsigned char)p->data[sizeof(unsigned char) + sizeof(unsigned long)];
	else
		return (unsigned char) p->data[0];
}

2.處理資料

接收到結構體

如果你最開始傳送了一個結構體,你可以通過如下程式碼轉化回這個結構體

if (GetPacketIdentifier(packet)==/* 使用者分配的資料包標示符 */)
	DoMyPacketHandler(packet);

// 放置在你想放置的任何地方,放在處理遊戲的狀態類中是個好地方.
void DoMyPacketHandler(Packet *packet)
{
	// 轉化資料為適當的結構體
	MyStruct *s = (MyStruct *) packet->data;
	assert(p->length == sizeof(MyStruct)); // 當你的傳輸結構體的時候這是個好習慣
	if (p->length != sizeof(MyStruct))
		return;

	// 使用你的結構體MyStruct *s處理資料包型別的函式在此呼叫
}

有用的註釋:

我們轉化資料包的資料為一個適當的指標型別,如果我們真的要建立這個結構體時,可以避免拷貝的開銷。然而在這個例子中,你修改了結構體中的任何資料,資料包中的內容也會被修改。這個可能不是我們想要的。作為一個伺服器,在中轉資料的時候要注意,可能會引起未知的錯誤。

儘管斷言不是必要的,當我們傳送一個數據包時,如果我們指定了錯誤的識別符號或者錯誤包長度,斷言對於捕獲非常難發現的bug是非常有效的。

當某些人設法傳送非法的長度或者型別為了讓客戶端或者伺服器宕機時,if語句是非常有效的。在實踐中,這種情況沒有發生過,但是沒有發生過並不代表是安全的。

接收到一個位元組流

如果你最初發送的是個位元組流,則需要建立一個位元組流,按照我們寫入的順序來解析資料。我們建立一個使用資料和資料包長度的位元組流。如果前面我們使用的是Write

函式,則使用Read函式來讀取他,如果使用了WriteCompressed函式,則使用ReadCompressed函式來讀取。如果我們有條件性的寫入任何資料,則接下來要使用同樣的邏輯分支來處理。下面的例子說明了處理Creating Packets章節中的地雷資料。

void DoMyPacketHandler(Packet *packet)
{
	Bitstream myBitStream(packet->data, packet->length, false); // false是為了效率,所以我們不復制傳遞的資料
	myBitStream.Read(useTimeStamp);
	myBitStream.Read(timeStamp);
	myBitStream.Read(typeId);
	bool isAtZero;
	myBitStream.Read(isAtZero);
	if (isAtZero==false)
	{
		x=0.0f;
		y=0.0f;
		z=0.0f;
	} else {
		myBitStream.Read(x);
		myBitStream.Read(y);
		myBitStream.Read(z);
	}

	myBitStream.Read(networkID); // 在結構體中這個是NetworkID networlId
    myBitStream.Read(systemAddress); // 在結構體中這個是SystemAddress systemAddress
}

3.釋放資料包

RakPeerInterface例項中得到的資料包,傳遞給DeallocatePacket(Packet* packet)函式,從而釋放該資料包。