The following procedure describes the most basic use of PiaTransport.
When using PiaInet, make sure to initialize it before initializing PiaTransport. Conversely, make sure to finalize PiaTransport before finalizing PiaInet.
When using PiaLocal, make sure to initialize it before initializing PiaTransport. Conversely, make sure to finalize PiaTransport before finalizing PiaLocal.
The various processes are described below.
The following sample code shows how to initialize PiaTransport.
void initializePiaTransport()
{ // Initialize PiaTransport. nn::Result result = nn::pia::transport::Initialize(); PIA_ASSERT(result.IsSuccess()); // Start the setup segment. result = nn::pia::transport::BeginSetup(); PIA_ASSERT(result.IsSuccess()); // Configure an instance of Transport. nn::pia::transport::Transport::Setting setting; setting.pFactory = pFactory; // Pointer to instances that inherit the NetworkFactory class. setting.maxStationNum = 8; // The maximum number of stations that can join a particular network. setting.maxSendThreadBufferNum = 16; // The size of the internal buffer for the sending thread. setting.maxReceiveThreadBufferNum = 32; // The size of the internal buffer for the receiving thread. setting.analysisInterval = 0; // Set to 0 to disable automatic printout of analysis data. // Create the Transport singleton. result = nn::pia::transport::Transport::CreateInstance(setting); PIA_ASSERT(result.IsSuccess()); // Code for initializing the protocol you will be using. ... ... // End the setup segment. result = nn::pia::transport::EndSetup(); PIA_ASSERT(result.IsSuccess()); } |
Use the Transport::Setting structure to configure the Transport singleton. The size of the buffer that you set affects the amount of memory consumed by PiaTransport. Make sure that you set a value large enough to handle the communications that take place in the application. A later subsection provides some hints about how to determine an appropriate value to set.
Call the Transport::CheckConnectionError() function in every game frame to check the connection status so you can respond to network disconnection events.
In PiaTransport, data is sent and received using instances of the transport::UnreliableProtocol class or the transport::ReliableProtocol class, both of which inherit from the transport::Protocol class. For more information, see Basic Features - UnreliableProtocol and Basic Features - ReliableProtocol.
The following sample code shows calls to the PiaTransport API that must occur every game frame.
while(true)
{ nn::pia::common::Scheduler::GetInstance()->Dispatch(); // First dispatch function call. // Check the PiaTransport connection status every game frame. nn::Result connectionStatus = nn::pia::transport::Transport::GetInstance()->CheckConnectionError(); if (connectionStatus.IsFailure()) { break; // End because the communication has been disconnected. } // Call a receive function in the UnreliableProtocol or ReliableProtocol class. ... // Update the game object. ... // Call a send function such as UnreliableProtocol or ReliableProtocol. ... nn::pia::common::Scheduler::GetInstance()->Dispatch(); // Second dispatch function call. } |
The following sample code shows how to finalize PiaTransport.
void finalizePiaTransport()
{ // Protocol finalization. ... ... // In Pia, Finalize and DestroyInstance always succeed. if (nn::pia::transport::Transport::GetInstance() != NULL) { nn::pia::transport::Transport::DestroyInstance(); } nn::pia::transport::Finalize(); } |
To prevent the parsing of data that has been tampered with, you can attach signatures to the Pia packets. Signatures are handled in the PiaTransport layer.
If the session API is being used for Internet communications, signatures are set automatically. If local communications are taking place, encryption is handled at a lower layer and signatures are disabled by default. However, you can enable them.
If, on the other hand, you are using the mesh API, have the application explicitly configure the signature setting. For more information, see the Programming Manual and API Reference for PiaSession.
Pia uses the MD5 algorithm to create and authenticate signatures. The 16-byte MD5 signature is stored in the packet payload region. The amount of space available in the payload for actually sending and receiving data in the application is reduced by this amount.
PiaTransport performs keep-alive communications automatically.
When there is no packet sending to other stations for a set period of time (the maximum silence time), a keep-alive packet is automatically generated and sent. The default send interval of the keep-alive packet is one second. The maximum silence time is ten seconds.
The interval for transmitting keep-alive packets and the communications timeout can be set by using the nn::pia::session::Session::Startup() function. For more information, see the API Reference for the Session class.
If you shorten the maximum silence time, you can improve the user experience because disconnections will be detected faster. On the other hand, because there are fewer opportunities to receive keep-alive packets, stations have less tolerance for lost packets. If you are going to shorten the maximum silence time, we recommend adopting a strategy so there is no unnecessary sacrifice of tolerance to packet loss, for example by shortening the interval at which keep-alive packets are sent.
PiaTransport temporarily stores data sent and received by the application. As a result, PiaTransport uses more memory than other modules. It consumes most of the memory used by Pia. PiaTransportmust be provided sufficient memory for its needs, and the application must use that memory efficiently.
This section gives hints for determining the appropriate memory size.
PiaTransport has two internal buffers: one for the thread for sending data and one for the thread for receiving data. A detailed description of how these buffers are used is not included, but their sizes can be specified as parameters in the Transport::Setting structure, which is passed when the Transport::CreateInstance() function is called. Before you begin tuning the memory size, we recommend that you set values that provide some leeway. The following sample shows configuration.
nn::pia::transport::Transport::Setting setting;
setting.pFactory = pFactory; // Pointer to instances that inherit the NetworkFactory class. setting.maxStationNum = 4; // The maximum number of stations that can join a particular network. setting.maxSendThreadBufferNum = 16; // The size of the internal buffer for the sending thread. setting.maxReceiveThreadBufferNum = 32; // The size of the internal buffer for the receiving thread. |
nn::pia::transport::Transport::Setting setting;
setting.pFactory = pFactory; // Pointer to instances that inherit the NetworkFactory class. setting.maxStationNum = 4; // The maximum number of stations that can join a particular network. setting.maxSendThreadBufferNum = 6; // The size of the internal buffer for the sending thread. setting.maxReceiveThreadBufferNum = 12; // The size of the internal buffer for the receiving thread. |
You can use the watermark feature to get the peak value for internal buffer usage in PiaTransport.
For more information about setting up the watermark feature, see 2.3. Watermarking. To begin measurements with the watermark features, execute it before initializing the PiaTransport module. After beginning measurements, execute a series of actual communication processes with the application. After communication is complete, or when you have executed sufficient communication for your measurements, the following code can be used to get measurement results.
void PrintWatermark()
{ nn::pia::common::WatermarkManager* pMgr = nn::pia::common::WatermarkManager::GetInstance(); if(PIA_IS_VALID_POINTER(pMgr)) { for(int i=0; i<=nn::pia::common::WatermarkManager::KEY_MAX; ++i) { nn::pia::common::Watermark* pMark = pMgr->GetWatermark(i); PIA_ASSERT(PIA_IS_VALID_POINTER(pMark)); if(pMark->GetUpdateCount() > 0) { PIA_SAMPLE_PRINT("Watermark: <%s> max: %lld, min: %lld, latest: %lld, Updates: %lld\n", pMark->GetName(), pMark->GetMaxValue(), pMark->GetMinValue(), pMark->GetLatestValue(), pMark->GetUpdateCount() ); } } } else { PIA_SAMPLE_PRINT("It seems that WatermarkManager instance is not ready.\n"); } } |
The following example shows results derived from this procedure.
Watermark: <SendThreadStream buffer num> max: 5, min: 2, latest: 5, Updates: 14342
Watermark: <ReceiveThreadStream buffer num> max: 6, min: 2, latest: 3, Updates: 15737 |
The value displayed to the right of max: is the peak value for buffer usage. When this peak value is equivalent to the internal buffer size specified as a member variable in the Transport::Setting structure, the whole internal buffer is used. Depending on the amount of communication by the application, the internal buffer may be about to run short. Conversely, if the peak value is much smaller than the specified internal buffer size, the internal buffer has sufficient leeway. Consider these results and set each of the members of the Transport::Setting structure appropriately.