WebSocketServerFactory listening on multiple ports at once?

#1

I am using WebSocketResource to map websockets into a standard Twisted resource hierarchy. One of the useful things you can do with a resource tree is expose it via HTTP on multiple ports at once. A simple example would be something like this:

root = resource.Resource()

site = server.Site(root)

http80 = internet.TCPServer(80, site)

http8080 = internet.TCPServer(8080, site)

Because the constructor to a WebSocketServerFactory requires a URL with the port the websocket will be listening on, I am having a hard time figuring out how to expose my websocket resource hierarchy on both ports 80 and 8080. Here is a code sketch of what I’m doing.

class MyResource(WebSocketResource):

def init(self, other, args):

hostname = socket.gethostname()

url_where_listening = “ws://%s:80” % hostname

f = WebSocketServerFactory(url_where_listening, debug=False, debugCodePaths=False)

f.protocol = MyProtocol

WebSocketResource.init(self, f)

root = resource.Resource()

root.putChild(“myresource”, MyResource(my, arguments))

site = server.Site(root)

http_service = internet.TCPServer(80, site)

http_service2 = internet.TCPServer(8080, site)

It seems that somehow I need the listening port of the URL to be a function of a particular request, and not fixed at initialization time.

I could always create two copies of the resource hierarchy since it’s dynamically generated anyway, but that seems strange.

Why two ports you may ask? I am finding that 3G service in the US oftentimes caches traffic on port 80 in such a manner that WebSockets do not work. WebSockets on port 8080 seem to be ok.

Thx - Tom

0 Likes

#2

I answered this for myself. The solution was to dynamically generate the WebSocketServerFactory based on the request. Since my resources were dynamically generated anyway, this didn’t add any overhead. I examine the request to find the port the request arrived on and then generate the WebSocketResource dynamically with the appropriate listening URL. Here’s a sketch of what I did, FYI.

class ParentResource(resource.Resource):

def getChild(self, path, request):

host = request.getHost()

port = host.port

m = MyResource(port)

class MyResource(WebSocketResource):

def init(self, port)

hostname = socket.gethostname()

url_where_listening = “ws://%s:%d” % (hostname, port)

f = WebSocketServerFactory(url_where_listening, debug=False, debugCodePaths=False)

f.protocol = MyProtocol

WebSocketResource.init(self, f)

root = resource.Resource()

root.putChild(“parentresource”, ParentResource())

site = server.Site(root)

http_service = internet.TCPServer(80, site)

http_service2 = internet.TCPServer(8080, site)

Now my resources are served up on two ports as I desired.

···

On Thursday, June 20, 2013 2:58:06 PM UTC-7, Tom Sheffler wrote:

I am using WebSocketResource to map websockets into a standard Twisted resource hierarchy. One of the useful things you can do with a resource tree is expose it via HTTP on multiple ports at once. A simple example would be something like this:

root = resource.Resource()

site = server.Site(root)

http80 = internet.TCPServer(80, site)

http8080 = internet.TCPServer(8080, site)

Because the constructor to a WebSocketServerFactory requires a URL with the port the websocket will be listening on, I am having a hard time figuring out how to expose my websocket resource hierarchy on both ports 80 and 8080. Here is a code sketch of what I’m doing.

class MyResource(WebSocketResource):

def init(self, other, args):

hostname = socket.gethostname()

url_where_listening = “ws://%s:80” % hostname

f = WebSocketServerFactory(url_where_listening, debug=False, debugCodePaths=False)

f.protocol = MyProtocol

WebSocketResource.init(self, f)

root = resource.Resource()

root.putChild(“myresource”, MyResource(my, arguments))

site = server.Site(root)

http_service = internet.TCPServer(80, site)

http_service2 = internet.TCPServer(8080, site)

It seems that somehow I need the listening port of the URL to be a function of a particular request, and not fixed at initialization time.

I could always create two copies of the resource hierarchy since it’s dynamically generated anyway, but that seems strange.

Why two ports you may ask? I am finding that 3G service in the US oftentimes caches traffic on port 80 in such a manner that WebSockets do not work. WebSockets on port 8080 seem to be ok.

Thx - Tom

0 Likes

#3

Hi Tom,

sorry for late answer: the reason WebSocketServerFactory needs the URL is because it does some checking of the URL requested by the client during the WebSocket opening handshake.

E.g., the WebSocket spec requires a port to be present in the HTTP GET URL sent by client if the server runs on a non-standard port (!= 80/443).

When try running the same WebSocketServerFactory with the same URL on different ports, it'll raise from these sanity checks.

We probably could add a switch to turn that off or override the "listening" URL on each WebSocketServerProtocol instance. If you wanna have that, please submit an issue on GitHub.

I answered this for myself. The solution was to dynamically generate
the WebSocketServerFactory based on the request. Since my resources

Does that create a new WebSocketServerFactory on each request, or is that created only upon first request to that resource (path) and cached within Twisted Web?

If the latter, thats a neat trick!

/Tobias

···

Am 21.06.2013 14:53, schrieb Tom Sheffler:

were dynamically generated anyway, this didn't add any overhead. I
examine the request to find the port the request arrived on and then
generate the WebSocketResource dynamically with the appropriate
listening URL. Here's a sketch of what I did, FYI.

class ParentResource(resource.Resource):

     def getChild(self, path, request):
        host = request.getHost()
        port = host.port
        m = MyResource(port)

class MyResource(WebSocketResource):

     def __init__(self, port)
         hostname = socket.gethostname()
         url_where_listening = "ws://%s:%d" % (hostname, port)
         f = WebSocketServerFactory(url_where_listening, debug=False,
debugCodePaths=False)
         f.protocol = MyProtocol

         WebSocketResource.__init__(self, f)

root = resource.Resource()
root.putChild("parentresource", ParentResource())
site = server.Site(root)

http_service = internet.TCPServer(80, site)
http_service2 = internet.TCPServer(8080, site)

Now my resources are served up on two ports as I desired.

On Thursday, June 20, 2013 2:58:06 PM UTC-7, Tom Sheffler wrote:

    I am using WebSocketResource to map websockets into a standard
    Twisted resource hierarchy. One of the useful things you can do
    with a resource tree is expose it via HTTP on multiple ports at
    once. A simple example would be something like this:

         root = resource.Resource()
         site = server.Site(root)
         http80 = internet.TCPServer(80, site)
         http8080 = internet.TCPServer(8080, site)

    Because the constructor to a WebSocketServerFactory requires a URL
    with the port the websocket will be listening on, I am having a hard
    time figuring out how to expose my websocket resource hierarchy on
    both ports 80 and 8080. Here is a code sketch of what I'm doing.

    class MyResource(WebSocketResource):

         def __init__(self, other, args):
             hostname = socket.gethostname()
             url_where_listening = "ws://%s:80" % hostname
             f = WebSocketServerFactory(url_where_listening,
    debug=False, debugCodePaths=False)
             f.protocol = MyProtocol

             WebSocketResource.__init__(self, f)

    root = resource.Resource()
    root.putChild("myresource", MyResource(my, arguments))
    site = server.Site(root)

    http_service = internet.TCPServer(80, site)
    http_service2 = internet.TCPServer(8080, site)

    It seems that somehow I need the listening port of the URL to be a
    function of a particular request, and not fixed at initialization time.

    I could always create two copies of the resource hierarchy since
    it's dynamically generated anyway, but that seems strange.

    Why two ports you may ask? I am finding that 3G service in the US
    oftentimes caches traffic on port 80 in such a manner that
    WebSockets do not work. WebSockets on port 8080 seem to be ok.

    Thx - Tom

--
You received this message because you are subscribed to the Google
Groups "Autobahn" group.
To unsubscribe from this group and stop receiving emails from it, send
an email to autobahnws+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

0 Likes

#4

Hi Tobias -

I am not being so clever as to cache the WebSocketServerFactory instance … I’m simply creating a new one on each requests. Requests are infrequent, and websockets are used for a long time, so this seems ok for now. Caching the instance is a really good idea … and would be simple to implement! Thanks.

T

···

On Saturday, June 22, 2013 1:41:28 AM UTC-7, Tobias Oberstein wrote:

Hi Tom,

sorry for late answer: the reason WebSocketServerFactory needs the URL
is because it does some checking of the URL requested by the client
during the WebSocket opening handshake.

E.g., the WebSocket spec requires a port to be present in the HTTP GET
URL sent by client if the server runs on a non-standard port (!= 80/443).

When try running the same WebSocketServerFactory with the same URL on
different ports, it’ll raise from these sanity checks.

We probably could add a switch to turn that off or override the
“listening” URL on each WebSocketServerProtocol instance. If you wanna
have that, please submit an issue on GitHub.

Am 21.06.2013 14:53, schrieb Tom Sheffler:

I answered this for myself. The solution was to dynamically generate

the WebSocketServerFactory based on the request. Since my resources

Does that create a new WebSocketServerFactory on each request, or is
that created only upon first request to that resource (path) and cached
within Twisted Web?

If the latter, thats a neat trick!

/Tobias

were dynamically generated anyway, this didn’t add any overhead. I

examine the request to find the port the request arrived on and then

generate the WebSocketResource dynamically with the appropriate

listening URL. Here’s a sketch of what I did, FYI.

class ParentResource(resource.Resource):

 def getChild(self, path, request):
    host = request.getHost()
    port = host.port
    m = MyResource(port)

class MyResource(WebSocketResource):

 def __init__(self, port)
     hostname = socket.gethostname()
     url_where_listening = "ws://%s:%d" % (hostname, port)
     f = WebSocketServerFactory(url_where_listening, debug=False,

debugCodePaths=False)

     f.protocol = MyProtocol
     WebSocketResource.__init__(self, f)

root = resource.Resource()

root.putChild(“parentresource”, ParentResource())

site = server.Site(root)

http_service = internet.TCPServer(80, site)

http_service2 = internet.TCPServer(8080, site)

Now my resources are served up on two ports as I desired.

On Thursday, June 20, 2013 2:58:06 PM UTC-7, Tom Sheffler wrote:

I am using WebSocketResource to map websockets into a standard
Twisted resource hierarchy.  One of the useful things you can do
with a resource tree is expose it via HTTP on multiple ports at
once.  A simple example would be something like this:
     root = resource.Resource()
     site = server.Site(root)
     http80 = internet.TCPServer(80, site)
     http8080 = internet.TCPServer(8080, site)
Because the constructor to a WebSocketServerFactory requires a URL
with the port the websocket will be listening on, I am having a hard
time figuring out how to expose my websocket resource hierarchy on
both ports 80 and 8080.  Here is a code sketch of what I'm doing.
class MyResource(WebSocketResource):
     def __init__(self, other, args):
         hostname = socket.gethostname()
         url_where_listening = "ws://%s:80" % hostname
         f = WebSocketServerFactory(url_where_listening,
debug=False, debugCodePaths=False)
         f.protocol = MyProtocol
         WebSocketResource.__init__(self, f)
root = resource.Resource()
root.putChild("myresource", MyResource(my, arguments))
site = server.Site(root)
http_service = internet.TCPServer(80, site)
http_service2 = internet.TCPServer(8080, site)
It seems that somehow I need the listening port of the URL to be a
function of a particular request, and not fixed at initialization time.
I could always create two copies of the resource hierarchy since
it's dynamically generated anyway, but that seems strange.
Why two ports you may ask?  I am finding that 3G service in the US
oftentimes caches traffic on port 80 in such a manner that
WebSockets do not work.  WebSockets on port 8080 seem to be ok.
Thx - Tom

You received this message because you are subscribed to the Google

Groups “Autobahn” group.

To unsubscribe from this group and stop receiving emails from it, send

an email to autobahnws+...@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.

0 Likes