%3CLINGO-SUB%20id%3D%22lingo-sub-2085930%22%20slang%3D%22en-US%22%3EHybrid%20relay%20control%20%26amp%3B%20rendezvous%20channel%20of%20Python%20edition%3C%2FLINGO-SUB%3E%3CLINGO-BODY%20id%3D%22lingo-body-2085930%22%20slang%3D%22en-US%22%3E%3CP%3EThis%20article%20will%20introduce%20the%20difference%20between%20control%20channel%20and%20rendezvous%20channel.%20And%20code%20a%20simple%20python%20application%20to%20interpret%20its%20process.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EPre-requirement%3A%26nbsp%3B%20understand%20azure%20relay%20%3CA%20href%3D%22https%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-relay%2Frelay-what-is-it%22%20target%3D%22_blank%22%20rel%3D%22noopener%20noreferrer%22%3Ehttps%3A%2F%2Fdocs.microsoft.com%2Fen-us%2Fazure%2Fazure-relay%2Frelay-what-is-it%3C%2FA%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EThe%20control%20channel%20is%20used%20to%20setup%20a%20WebSocket%20to%20listen%20the%20incoming%20connection.%20It%20allows%20up%20to%2025%20concurrent%20listeners%20for%20one%20hybrid%20connection.%20The%20control%20channel%20takes%20response%20from%20step%20%231%20to%20%235%20in%20following%20architecture.%3C%2FP%3E%0A%3CP%3E%3CSPAN%20class%3D%22lia-inline-image-display-wrapper%20lia-image-align-inline%22%20image-alt%3D%22Hai_Yue_0-1611302951299.png%22%20style%3D%22width%3A%20400px%3B%22%3E%3CIMG%20src%3D%22https%3A%2F%2Ftechcommunity.microsoft.com%2Ft5%2Fimage%2Fserverpage%2Fimage-id%2F248497iAEAC45E87A81E4AD%2Fimage-size%2Fmedium%3Fv%3D1.0%26amp%3Bpx%3D400%22%20role%3D%22button%22%20title%3D%22Hai_Yue_0-1611302951299.png%22%20alt%3D%22Hai_Yue_0-1611302951299.png%22%20%2F%3E%3C%2FSPAN%3E%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EWhen%20a%20sender%20open%20a%20new%20connection.%20The%20control%20channel%20chose%20one%20active%20listener.%20The%20active%20listener%20will%20setup%20a%20new%20WebSocket%20as%20rendezvous%20channel.%20The%20messages%20will%20be%20transferred%20via%20this%20rendezvous%20channel.%20The%20rendezvous%20channel%20takes%20response%20from%20step%20%236%20to%20%239%20in%20above%20architecture.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3EBelow%20is%20a%20simple%20Python%20application%20to%20realize%20control%20channel%20and%20rendezvous%20channel%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%3E%0A%3CLI%3EBelow%20code%20will%20create%20a%20control%20channel.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20wss_uri%20%3D%20'wss%3A%2F%2F%7B0%7D%2F%24hc%2F%7B1%7D%3Fsb-hc-action%3Dlisten'.format(service_namespace%2C%20entity_path)%20%2B%20'%26amp%3Bsb-hc-token%3D'%20%2B%20urllib.quote(token)%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20ws%20%3D%20WebSocketApp(wss_uri%2C%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20on_message%3Don_message%2C%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20on_error%3Don_error%2C%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20on_close%3Don_close)%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3COL%20start%3D%222%22%3E%0A%3CLI%3EFollowing%20is%20control%20channel%E2%80%99s%20on_message%20callback%20function.%20The%20sender%20connection%20on%20the%20control%20channel%20will%20contains%20a%20%3CSTRONG%3Eurl%3C%2FSTRONG%3E.%20The%20url%20is%20the%20rendezvous%20url%20need%20to%20be%20established.%3C%2FLI%3E%0A%3C%2FOL%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-30px%22%3E%26nbsp%3B%20The%20callback%20function%20will%20use%20%3CSTRONG%3Ecreate_connection%3C%2FSTRONG%3E%20to%20create%20a%20new%20WebSocket%20on%20this%20rendezvous%20url.%20After%20finish%20creating%20rendezvous%20channel%2C%20the%20WebSocket%20will%20call%20%3CSTRONG%3Erecv()%3C%2FSTRONG%3E%20%26nbsp%3Bto%20receive%20messages.%3C%2FP%3E%0A%3CP%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3Edef%20on_message(ws%2C%20message)%3A%26nbsp%3B%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20data%20%3D%20json.loads(message)%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%3CSTRONG%3Eurl%3C%2FSTRONG%3E%20%3D%20data%5B%22accept%22%5D%5B%22address%22%5D%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20ws%20%3D%20None%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20try%3A%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20ws%20%3D%20%3CSTRONG%3Ecreate_connection%3C%2FSTRONG%3E(url)%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20connected%20%3D%20ws.connected%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20if%20connected%3A%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20receive_msg%20%3D%20ws.%3CSTRONG%3Erecv()%3C%2FSTRONG%3E%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%2F%2Fprocess%20message%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%E2%80%A6.%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20ws.send(message_process_result)%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20else%3A%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%20%26nbsp%3B%20%26nbsp%3Bexcept%20Exception%2C%20ex%3A%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-90px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%E2%80%A6%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%20%26nbsp%3B%20%26nbsp%3Bfinally%3A%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-90px%22%3E%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%26nbsp%3B%20%E2%80%A6%3C%2FP%3E%0A%3CP%20class%3D%22lia-indent-padding-left-60px%22%3E%26nbsp%3B%3C%2FP%3E%0A%3CP%3ESome%20times%2C%20the%20callback%20function%20will%20be%20triggered%20even%20sender%20dose%20not%20send%20any%20message.%20It%20is%20actually%20control%20channel%20notifications.%20For%20example%2C%20if%20the%20relay%20server%20wait%20long%20time%20and%20can%E2%80%99t%20get%20response%20from%20listener%2C%20it%20will%20send%20a%20%E2%80%9Clistener%20not%20response%20immediately%E2%80%9D%20notification%20to%20listener%20side%20when%20listener%20recover.%3C%2FP%3E%3C%2FLINGO-BODY%3E
Microsoft

This article will introduce the difference between control channel and rendezvous channel. And code a simple python application to interpret its process.

 

Pre-requirement:  understand azure relay https://docs.microsoft.com/en-us/azure/azure-relay/relay-what-is-it

 

The control channel is used to setup a WebSocket to listen the incoming connection. It allows up to 25 concurrent listeners for one hybrid connection. The control channel takes response from step #1 to #5 in following architecture.

Hai_Yue_0-1611302951299.png

 

 

When a sender open a new connection. The control channel chose one active listener. The active listener will setup a new WebSocket as rendezvous channel. The messages will be transferred via this rendezvous channel. The rendezvous channel takes response from step #6 to #9 in above architecture.

 

Below is a simple Python application to realize control channel and rendezvous channel

 

  1. Below code will create a control channel.

    wss_uri = 'wss://{0}/$hc/{1}?sb-hc-action=listen'.format(service_namespace, entity_path) + '&sb-hc-token=' + urllib.quote(token)

    ws = WebSocketApp(wss_uri,

                      on_message=on_message,

                      on_error=on_error,

                      on_close=on_close)

 

  1. Following is control channel’s on_message callback function. The sender connection on the control channel will contains a url. The url is the rendezvous url need to be established.

 

  The callback function will use create_connection to create a new WebSocket on this rendezvous url. After finish creating rendezvous channel, the WebSocket will call recv()  to receive messages.

 

def on_message(ws, message): 

    data = json.loads(message)

    url = data["accept"]["address"]

    ws = None

    try:

        ws = create_connection(url)

        connected = ws.connected

        if connected:

            receive_msg = ws.recv()

            //process message

            ….

            ws.send(message_process_result)

        else:

     except Exception, ex:

    …

     finally:

        …

 

Some times, the callback function will be triggered even sender dose not send any message. It is actually control channel notifications. For example, if the relay server wait long time and can’t get response from listener, it will send a “listener not response immediately” notification to listener side when listener recover.