NetworkDesign
請注意:此頁面說明了底層網絡通信。 如果您想使用Marauroa編寫遊戲,則無需理會這些實現細節。 無論如何,我們都會記錄網絡設計,以供Marauroa本身的貢獻者使用。 這對於將Marauroa移植到其他程式語言的人們很有幫助。
Messages[編輯]
Marauroa使用消息在客戶端和伺服器之間進行通信。 從客戶端發送到伺服器的消息以C2S為前綴,從伺服器發送到客戶端的消息以S2C為前綴.
每個消息都在包marauroa.common.net.message中的Java類中實現。 您可以在 javadoc 中查找有關每條消息的詳細信息. 如果要將Marauroa移植到另一種程式語言,則需要知道如何精確地序列化消息. 最簡單的學習方法是查看 source code 中的 readObject() 和 writeObject() 方法.
遊戲有不同的客戶端狀態:已連接,已登錄,遊戲中,已退出。 不同狀態下的有效消息也不同:
已連接狀態[編輯]
由於安全性要求,登錄過程有點複雜。 不要害怕,只要遵循以下的步驟即可.
一旦建立了TCP連接,客戶端就會使用以下命令向伺服器請求RSA公鑰 C2SLoginRequestKey. 伺服器檢查每個消息中隱式包含的協議版本. 如果兼容,它會回復一個 S2CLoginSendKey 包含 RSA 公鑰. 它由兩個字節數組組成: 第一個包含 'n' 的值, 第二個包含 'e' 的值.
客戶端計算 nonce (隨機數) 並將其哈希值作為字節數組發送到伺服器 C2SLoginPromise . 伺服器會記住客戶端的隨機數,並在 S2CLoginSendNonce 回復伺服器的nonce.
差不多可以了: 客戶端現在擁有了實際發送消息所需的所有信息。 C2SLoginSendNonceNameAndPassword: Its nonce, the username and the value rsaCrypt(xor(xor(client nonce, server nonce), password)). The first field is a bytes array containing the client nonce, the second one a string containing the username and the third one a byte array containing the encrypted password. On reception, the server checks that the hash he received at first is the hash of the nonce he just received. It then decodes the password field, and having the value of the client nonce and its nonce, it gets the value of the password.
The S2CLoginNACK message is sent from the server to the client to tell the client that its login request was rejected because the username or password is wrong, the account was banned or the server is full. The included result object will tell which of the cases prevented the login.
If the username/password combination, however, is correct then the Server must send a S2CLoginACK message to tell the client that the message has been correctly processed. It contains information about the last login, so that the user is able to recognize unauthorized usage of his account. The client state is changed to "logged in" in this case.
State logged in[編輯]
The logging in stuff was complicated. But luckily things are getting much easier now. After the login completed successfully the server sends a S2CServerInfo message. It tells the client about what kind of server is running, and details on how to contact the server administrator (e.g. their email address). The message is composed of a List of strings of the form "attribute=value". In addition this message also contains the list of defined RPClasses.
Directly afterwards a S2CCharacterList message is sent from the server to the client. It offers a choice of character to play with. This feature models the behavior of having several characters associated with a single account. Each character name must be unique at server level, and it is assigned when the character is created.
Now the client picks one of the offered characters. Games that do not support multiple characters can pick the one that matches the account name. The choice is transmitted to the server using a C2SChooseCharacter message. The name of the character must be one of the names listed in the character list.
The server will check the selected character and reply for a S2CChooseCharacterNACK if the choice was invalid. This implies that the client should send another C2SChooseCharacter message.
If the selection, however, was successful, a ChooseCharacterACK message is sent and the client state changed to "in game".
遊戲中[編輯]
常規消息[編輯]
The S2CPerception message is a message sent from the server to the client to notify the client about changes to the objects that exist near it. The message is based on the idea explained in the Delta Perception document.
The message is composed of:
- A type that can be DELTA or TOTAL
- A string indicating the name of the zone the perception is related to.
- A time stamp value that will be just one unit bigger than the previous perception
- A List of RPObject that contains added object
- A List of RPObject that contains modified added object attributes
- A List of RPObject that contains modified deleted object attributes
- A List of RPObject that contains deleted object
- A RPObject that describes the things the rest of players don't see about OUR own object.
Read the Delta perception algorithm to understand what it is for.
The client sends C2SKeepAlive messages regularly. If there has been no keep alive message for some time, the server will timeout the client.
靜態內容傳輸[編輯]
Perceptions are about dynamic content. But most games have some static data, too. Like maps, tilesets, sounds. The RPManager keeps track of situation in which the client might need some of this static data. A common case is the movement of the client from one zone to another.
If the RPManager detects such a situation, it will offer the new content to the client using a S2CTransferREQ message. The message is composed of an array of TransferContent objects containing the name of each resource, its timestamp (or checksum) and if the resource is cacheable or not.
The clients replies with a C2STransferACK acknowledging the offer. The message is composed of an array of TransferContent objects containing all the name of each resource and a flag indicating ack or not. Note: The C2STransferACK message is always sent, even if all flags indicate that no transfer should take place.
If the clients has acknowledged the need for content to be transfer, the server sends a S2CTransfer. The message contains a again an an array of TransferContent objects. This time, however, the actual data is included as well.
動作[編輯]
Actions are commands sent from the client to the server using a C2SAction message. Example for commands are "move to the right", "look at that object", "attack that rat". It is up to the server to decide whether to execute the action or reject it.
退出登錄[編輯]
If the player is in some kind of combat it is often desirable to prevent him from saving his live by logging out. Therefore the client sends a logout request to the server and the game server can decide whether to accept or reject it. Of course the user can close the client window or force a disconnect of his Internet connection. But in these cases he will simple stay in a game unattended until the timeout anyway.
The clients indicates that it wants to finish the session by sending a C2SLogout.
The server can reply with a S2CLogoutNACK to reject the logout request. Or it confirms the request with a S2CLogoutACK. In this case the client state is changed to logged out.
Transmitting Messages over TCP[編輯]
The idea behind Arianne's network protocol is to use a single TCP stream between the server and the clients. Different kinds of in-game actions create different types of messages that are then interpreted at the opposite side in to meaningful data. TCP takes care of sorting the packets and retransmitting lost ones.
Each message has a general header:
- Size of message (4 bytes)
- Protocol version (1 byte)
- Type of message (1 byte)
- Client ID (4 bytes)
- Timestamp (4 bytes)
This header is followed by message specific data. Have a look at the source code of the methods readObject() and writeObject() of the message in question.
網絡管理器[編輯]
The Network Manager is our router that sends and receives messages to and from the network. The manager exposes the interfaces that allow:
- Reading a message from the network
- Sending a message to the network
- Finalizing the manager
The read operation is a blocking type operation so we have two options, either polling (i.e. continually checking if data is there) or blocking (i.e. only processing when data is actually available, otherwise sleeping).
We choose blocking because we don't want to waste CPU time polling the network for messages, we just want to sleep until messages are available. Hence we create a Thread to read from the Network, let's call it NetworkManagerRead.
將消息寫入網絡可以簡單地編碼為網絡管理器的一種方法,因為寫入是一種本質上不會阻塞的操作.
NetworkManager將打開一個套接字,它將從中接收來自網絡的所有消息。 它還將從同一套接字將所有出站消息寫入網絡。 注意:寫入和讀取都使用相同的套接字.
為了封裝所有這些內容,我們將Read和Write方法都創建為Network Manager的內部類。.
NetworkManager { socket messages pendingToSendMessages NetworkManagerRead isa Thread { read socket build message store in messages } NetworkManagerWrite isa Thread { get from pendingToSendMessages serialize message send socket } }
如您所見,收到消息後,消息將存儲在列表中。 因此,對列表的訪問必須同步.
現在,讓我們回到暴露給其他對象的界面。 write方法是即時的,只需在發送消息時調用它即可,並確保已正確填寫SourceAddress和ClientID。 然後,該消息將發送給客戶端.
read方法處於阻塞狀態,當您調用read方法時,它要麼從隊列中返回一條消息,要麼如果隊列為空,則線程阻塞(休眠)直到一個到達.
這是網絡管理器的基本思想。 請注意,管理器僅發送一次數據包流,並且不確認是否接收到任何消息。 TCP負責確認. {{#breadcrumbs: Marauroa | Internals | Network Design }}