Search Unity

Unity Multiplayer LLAPI Make unreliable channel wait for reliable?

Discussion in 'Connected Games' started by HiddenMonk, Sep 29, 2015.

  1. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    975
  2. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    yes, you are right, it is one of existed problems. Reliable messages waiting for ack will block incoming unreliable messages. we're still thinking how we can avoid this problem without affect performance.
     
  3. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    975
    So when sending packets over a reliable channel, all unreliable packets in a unreliable channel will go in a buffer until the reliable is received?
    In my case, this is the behaviour I wanted, but I can see how it would be nice to also have a unreliable channel unaffected by the reliable.

    Thank you for the help =)
     
  4. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    Not 100% true :)
    Rough algorithm is:
    User: put message in the outgoing queue regardless is message reliable or not, if queue is full, send() will failed
    Network: grab message from this queue, if message unreliable, put this message in the packet and send
    if message is reliable, try to put message in buffer waiting for acknowledgement, put message to packet, then send
    if acknowledgment buffer is full, no new messages (regardless their reliability) will pop from the queue, so everything will stall before there will be ack come in and acknowledgement buffer will have space for new reliable message.

    I'm thinking to divide queue for reliable and unreliable messages so in case if reliable messages will stalling, user will be able to send unreliable, but it still will affect performance a little bit :(
     
  5. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    975
    I see, so I would need to create my own system to where my unreliable channel will wait on the target users machine until a reliable packet is received in case those unreliable packets relied on the reliable packet. Either that or I can just constantly send the reliable data inside the unreliable channel.

    A reason for this is something like spawning something in and then having packets rely on that object being spawned.
    Since my network system doesnt have an id or something for every networkbehaviour, I rely on each client having everything set up properly. If they arent, then the bitstream will be read wrong and even cause errors.

    Its very delicate, but its to be peer to peer (non authorative) and to try and remove the need for each network behaviour needing an id / size (to lower bandwidth).

    Im not sure how unet handles things with their hlapi, but I am assuming there are many ids and sizes being declared in the packets.
     
    Last edited: Sep 29, 2015
  6. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    The easiest way to reach this goal - add just byte counter to each message which you send, and drop all unreliable messages in receiver which counter is obsolete and keep reliable message in buffer which order is wrong

    sender:
    message-1 (r) 0
    message-2 (r) 1
    message-3 (u) 2
    message-4 (u) 3
    message-5 (r) 4

    receiver
    message-2 (correct) (store in ordered buffer)
    message-1 (correct)
    delver to user message-1, message-2
    message-4 (correct)
    message-3 (drop it - out of the order in unreliable)
    message-5 - correct

    It is quite similar how UNET keeps packet order in sequenced channels. Other option just send all your data via one reliable sequenced channel....
    >but I am assuming there are many ids and sizes being
    id - yes, but generic size only one - message size :)
     
  7. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    975
    What happens when its something like this?

    sender:
    message-1 (r) 0
    message-2 (r) 1
    message-3 (u) 2
    message-4 (u) 3
    message-5 (r) 4

    receiver
    message-3 - unreliable packet received, doesnt know there was meant to be a reliable packet before it so it uses this one. However, this unreliable packet relies on reliable packet message-1. Now that message-3 is running without message-1, all gets messed up
    message-2 - reliable packet received, but it was already to late...
    ....
    ....

    What I am thinking I may need to do is when a reliable packet is sent out, all unreliable packets need to have something in them to let the other client know to wait for a reliable packet before running these unreliable.
    Something like a bitmarker stating whether this unreliable packet is relying on some reliable packet. If 0, it is not, if 1 then read in a list of reliable packet id's. If all reliable packet id's are received then you can either run these unreliable, or just drop them and run the newest unreliable. Onces the ack is returned to the sender, it will go back to a 0 bitmarker.

    Or just stop sending out unreliable packets until that special reliable packet ack is received.
    Either way, I would probably want to avoid adding and removing networkbehaviours. (when I say networkbehaviours, I mean my own custom networkbehaviour, not unitys).

    Im guessing (may be wrong) you are doing things similar to how I was setting things up in where keeping things the same on each client is very important. We just let each networkbehaviour read what it needs from the bitstream and trust that each will take what it gave in. This is why I am trying to do this unreliable waiting for reliable. Since I am not declaring a size for each networkbehaviour, if a networkbehaviour unsubscribes, but the other clients dont know in time as shown in the example above, all networkbehaviours will be messed up. Very delicate ^^.

    Though, do you mean every networkbehaviour has an id, or is it just the networkidentity? In my case, its just the networkidentity with the id and I rely on the networkbehaviours assigned to the networkidentity to be setup properly on all clients. If you have each networkbehaviour have an id then I can see how you wont have the issue I am having.
     
    Last edited: Sep 30, 2015
  8. aabramychev

    aabramychev

    Unity Technologies

    Joined:
    Jul 17, 2012
    Posts:
    574
    Gotcha :)
    I would say, if you send a lot of reliable "sync" messages, try just using reliable sequenced qos for all messages. If only few, use unreliable sequenced qos for major, reliable sequenced for sync and "..just stop sending out unreliable packets until that special reliable packet ack is received."

    And only in case you will see performance degradation of your system, try to do something more fancy...

    ========
    Second part related to HLAPI :) not my area of expertise :) so I just don't know all nuances there :)
     
  9. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    975
    Ye, thats most likely the route I will go =)
    ^^ np, thank you for your help!
     
  10. caseyc

    caseyc

    Joined:
    Jul 2, 2012
    Posts:
    15
    I know this thread is old but I am in a similar situation.
    How do I know when the reliable packet ack has been received? I have looked everywhere but it seems like that information is hidden.
     
  11. Ashkan_gc

    Ashkan_gc

    Joined:
    Aug 12, 2009
    Posts:
    924
    IMHO the queues should be separate in order to not block unreliable messages. The perf will degrade a bit but the whole point of unreliable and AllCostDelivery is to send a message ASAP and waiting for an ack specially on mobile platforms/wireless networks can be a good amount of time in some cases.
     
  12. HiddenMonk

    HiddenMonk

    Joined:
    Dec 19, 2014
    Posts:
    975
    Is it possible that we can get a new QosType called something like "ReliableWait" that basically stops sending all messages until the ReliableWait packet Ack was received?
    Otherwise I think we are pretty much forced to make our own message send queue, Ack system, etc =(

    Also, this is all assuming that NetworkTransport.Send immediately places the message in a queue, meaning the message order is predictable so QosType.ReliableWait could actually work. If NetworkTransport.Send doesnt preserve the order we called it, such as it groups QosTypes together, then QosType.ReliableWait wouldnt work and we would have to design our own send queue, ack system, etc...

    -Edit
    It might not be too hard to make something like this ourselves.

    Instead of having a new QosType, we can make a custom NetworkTransport.Send method that has a extra parameter bool waitForReliable.
    If waitForReliable is true and the channel QosType is some form of reliable, we can wrap the packet within a custom message that tells the receiving connection to send a confirmation reliable message of them receiving the packet.
    Meanwhile, any other calls to our custom NetworkTransport.Send method will be put into a queue and wont be sent out until we received the confirmation packet. This queue will also have the same maxSendQueueSize as the original NetworkTransport send queue.

    This might be slow since we are using reliable packets as a means of sending an Ack, but its a lot simpler then making our own Ack system, and something like this is only really meant to be used a couple of times for important messages.
     
    Last edited: Jun 7, 2017