7. Direct Streaming

Direct streaming provides features for simple sending and receiving.

7.1. Enabling and Disabling

You must first call the DirectStream::Enable function before you can send or receive using direct streaming. Calling DirectStream::Enable enables you to send and receive using direct streaming. Until this function is enabled, received packets are discarded within the library.

When you do not need direct streaming anymore, call the DirectStream::Disable function to disable sending and receiving using direct streaming. However, even when disabled, any data already accumulated in the send queue is still sent. On the receiving end, responses to arrival confirmations for Reliable communication, described later, are handled within the library.

7.2. Communication Types

Direct streaming supports two types of communication. The following sections describe the characteristics of each type.

You can select whether to use the PRUDP protocol implemented on UDP, with or without reliability.

7.2.1. Unreliable Communication

Data sent is not guaranteed to arrive.

Use this for more efficient communication when you do not need to guarantee delivery.

With standard settings, both duplicate packets and packets that are out of order arrive

Perform the following configuration to guarantee that packets are in the right order and to resolve problems where packets are received out of order or the same packet is received several times. With this configuration, packets for which the order is unusual are destroyed starting from the oldest packet.

RootTransport::EnableDropDuplicateReorderingUnreliablePackets(true);

7.2.2. Reliable Communication

Data sent is guaranteed to arrive.

It is guaranteed that the order the packets are sent is the order in which they arrive. Also, lost packets are resent and duplicate packets are destroyed.

Because a transmission error can occur when the network is clogged because of packet transmission performance or a lost occurrence state, you must use a retry process in addition to error handling when performing frequent transmissions.

7.3. Sending

7.3.1. Sending to Specific Stations (No Call Context Specified)

Call the DirectStream::Send function to send packets to a specific station participating in the session. This function returns successfully after the data to send is added to the send queue, and returns an error if the function could not add the data to the queue. Send data added to the send queue is sent when either the Scheduler::Dispatch function or the Scheduler::DispatchAll function is called.

You can specify all of the communication types in calls to the DirectStream::Send function.

The DirectStream::SendUnreliable is a function for unreliable sends without specifying call context.

7.3.2. Sending to Specific Stations (Call Context Specified)

There is an overloaded version of the DirectStream::Send function that allows you to specify a call context. This function returns true after the data to send is added to the send queue, and returns false if the function could not add the data to the queue.

Using a call context allows you to use an asynchronous process to receive arrival confirmations for packets sent using reliable communication. Use a context when you want to explicitly use arrival confirmations in your game application. After arrival is confirmed, the call context changes to the CallSuccess state. After calling the DirectStream::Disable function, the asynchronous process that receives arrival confirmations stops. In that case, you must cancel the call context from the game application side.

Other communication types besides reliable do not need arrival confirmation, so the results of adding data to the send queue are returned to the call context.

7.3.3. Sending to All Stations

Call the DirectStream::SendUnreliableAll function to send unreliable packets to all stations participating in the session. This function returns successfully after the data to send to all stations is added to the send queue, and returns an error if the function could not add the data to the queue.

You cannot specify a call context when sending to all stations.

7.3.4. Multiple Reliable Communications

With the standard settings, because the reliable queue is a single queue, if the network environment is bad, subsequent data never arrives because of head-of-line blocking.

By using multiple separate reliables (each reliable is called a substream), independent resend control can be performed. Instead of guaranteeing arrival order between substreams, clogging can be avoided for transmissions by resending important data. By specifying the user substream count used by the StreamSettings::SetMaxUserReliableSubStreams function when initializing NetZ, a maximum of 256 reliable communications to match the system shared substreams at initialization (ID is SubStreamIDDefine::SYSTEM) are possible.

Reliable communications that specify SubStreamID are performed with the DirectStream::SendReliable function.

If the system and shared substreams are clogged because a delay occurs in the fault recovery process, use at least one user substream, and exchange data by using that substream.

The following examples of SubStreamID are able to use 0 to 2 substreams. SubStreamID 0 (= SubStreamIDDefine::SYSTEM) is shared with the system, and is the same as when reliable communications are performed with the DirectStream::Send function.

Code 7.1 Initialization Example When Using Multiple Substreams

NetZ                *poNetZ = qNew NetZ;
Stream::GetSettings().SetMaxUserReliableSubStreams(2);

....
// The JoinSession or CreateSession process.

When the communication partner and the StreamSettings::SetMaxUserReliableSubStreams function value differ, the smallest is determined to be the greatest substream ID by negotiation. QERROR(Transport, InvalidSubStreamID) occurs when an ID exceeding the greatest substream ID is specified during sends.

To view sample code, see the AutoMatch sample.

Warning

To send data immediately after communication completes, use the SubStreamIDDefine::SYSTEM (=0) that is shared with the system. On occasion, the data may not arrive by the time communication completes.

An excessive number of substreams consumes memory, so use a suitable number.

Also, NEX reliable communications perform resend control but do not perform collision congestion control. For this reason, when multiple substreams are in parallel and too much data clogs, resends occur frequently and the loss rate increases. When sending a large volume of data, use a single substream.

7.3.5. Maximum Sending Size

The maximum sending size for unreliable communication is limited by the MTU. Because a NEX header is included in the MTU, be sure to use a transmission size of 1300 bytes or less if the topology of the NetZ network is peer-to-peer, or 1250 bytes or less in other cases.

For reliable communication, you can specify a buffer size of up to 32768 bytes when sending, but the portion larger than the MTU is split into chunks for sending.

7.3.6. Maximum Number of Reliable Communication Send Buffers

When the maximum number of send buffers has been reached for sending reliable communication data, the sending process returns the ReliableSendBufferFull error.

The ReliableSendBufferFull error indicates that the send buffer was temporarily full, so when this error occurs, dispatch the data and then wait briefly before trying to send the data again. The reliable communication send buffer also includes reliable communication packets used internally by NEX, in addition to packets sent by direct stream.

You can get the number of packets in the send buffer during reliable communications by using the DirectStream::GetPendingReliableBufferNum function. The value that is obtained by using the DirectStream::GetPendingReliableBufferNum function includes reliable communication packets that are used internally in NEX, in addition to unreliable communication packets that are used for direct streaming.

Call the DirectStream::SetMaxReliableSendBufferNum function to change the maximum number of reliable communication send buffers. The standard default value is usually enough, because not many reliable communication packets are used internally by NEX. Do not set a value greater than 96. Call the DirectStream::GetMaxReliableSendBufferNum function to get the current value.

Except for certain P2P communications, the buffer for packets is managed by the packet buffer manager in a fixed-length memory pool. As long as there is enough space in the packet buffer, no error is thrown until the maximum number of send buffers is reached for reliable communication. QRESULT_ERROR(Transport, PacketBufferFull) is returned when the packet buffer runs out of space. If PacketBufferFull is thrown, dispatch the data and wait briefly before trying to send the data again. If PacketBufferFull occurs frequently, increase the size of the packet buffer. For more information about the packet buffer, see Managing Packet Buffer Memory in Memory Management.

7.3.7. Factors Causing Errors When Sending

Sending fails and returns an error in the following cases.

  • When the function is called before the NetZ object has finished being created, or while the NetZ object is in the process of being destroyed.
  • When the data to send is a null value.
  • When the amount of data to send exceeds the amount that can be sent. (For more information, see Section 7.3.6 Maximum Number of Reliable Communication Send Buffers.)
  • During reliable communication, when the reliable send buffers are full. (For more information, see Section 7.3.6 Maximum Number of Reliable Communication Send Buffers.)
  • When sending to one's own station.
  • When the local station has not joined a P2P session.
  • When the recipient is a station that has not joined the P2P session.
  • When specifying reliable communication in calls to the DirectStream::SendAll function.
  • When specifying a SubStreamID with the DirectStream::SendReliable function that exceeds the greatest substream ID.
  • When the packet buffer is exhausted (and returns the PacketBufferFull error).

The call context is specified when sending data. An error is returned to the call context if communication with the destination station is lost.

When using reliable communication to send data, the ReliableSendBufferFull error is returned if the send buffer is full. The ReliableSendBufferFull error indicates that the send buffer was temporarily full, so when this error occurs, dispatch the data and then wait briefly before trying to send the data again.

PacketBufferFull is thrown when the packet buffer runs out of space. The PacketBufferFull error indicates that the packet buffer was temporarily full. When this error occurs, dispatch the data and wait briefly before trying to send the data again if necessary. If PacketBufferFull occurs frequently, increase the size of the packet buffer. For more information about the packet buffer, see Managing Packet Buffer Memory in Memory Management.

7.4. Receiving

Received packets are stored in the direct stream receive buffer when either the Scheduler::Dispatch function or the Scheduler::DispatchAll function is called. You can get received data stored in the receive buffer by calling the DirectStream::GetReceivedData function. With the DirectStream::Data structure, you can get the sender's StationID, transmission type, packet buffer, and SubStreamID from the received data.

The direct stream receive buffer is not cleared until the DirectStream::GetReceivedData function is called. You must be sure to periodically call the DirectStream::GetReceivedData function along with the Scheduler::Dispatch or Scheduler::DispatchAll function so that calls to the Scheduler::Dispatch and Scheduler::DispatchAll functions do not cause too much receive data to accumulate in the direct stream receive buffer. The fatal error QRESULT(Transport, NoBuffer) is generated when the receive buffer overflows.

For more information about handling fatal errors, see Chapter 4 Error Handling.

If the receive buffer overflows, reduce the number of packets sent from other Stations, or increase how often the DirectStream::GetReceivedData function is called along with the Scheduler::Dispatch function or Scheduler::DispatchAll function.


CONFIDENTIAL