Question

I'm trying to translate the following example HTTP server based on 0MQ written in C seen here: Hintjens' blog into Python.

def test_http_socket():
    ctx = zmq.Context()
    sock = ctx.socket(zmq.ROUTER)
    sock.setsockopt(zmq.ROUTER_RAW, 1)
    sock.bind("tcp://*:8080")
    while True:
        id_bytes = sock.recv()
        print("id=",id_bytes)
        request = sock.recv()
        print("request=",request)
        if b'/close' in request:
            return
        sock.send(id_bytes, zmq.SNDMORE)
        sock.send(b"""HTTP/1.0 200 OK
Content-Type: text/plain

Hello, world !""")
        sock.send(zmq.NULL)

The problem is on the next line, where I try to translate the C expression

zmq_send (router, NULL, 0, 0);

In Python I have the following stack trace:

Traceback (most recent call last):
  File "<pyshell#96>", line 1, in <module>
    test_http_socket()
  File "<pyshell#95>", line 18, in test_http_socket
    sock.send(zmq.NULL)
  File "socket.pyx", line 565, in zmq.backend.cython.socket.Socket.send     (zmq\backend\cython\socket.c:5104)
  File "socket.pyx", line 612, in zmq.backend.cython.socket.Socket.send (zmq\backend\cython\socket.c:4868)
  File "socket.pyx", line 168, in zmq.backend.cython.socket._send_copy (zmq\backend\cython\socket.c:1914)
  File "buffers.pxd", line 200, in buffers.asbuffer_r (zmq\backend\cython\socket.c:6833)
  File "buffers.pxd", line 151, in buffers.asbuffer (zmq\backend\cython\socket.c:6270)
TypeError: 0 does not provide a buffer interface.

In fact, sock.send can only be used to send buffers or messages. Is there a way to use 0MQ's zmq_send in another manner from Python, to send a NULL frame ?

By the way, a comment in Github entry shows that it may not close the connection to the client even in C. How can I ask the remote client to close its connection (in Python) ?

I'm using libzmq 4.0.1 and PyZMQ 14.0.1 over Python 3.3.2 on Windows 32bits.

Was it helpful?

Solution

First point: zmq.NULL is the ZMQ_NULL constant, for use in zeromq's security mechanism. For example:

socket.mechanism = zmq.NULL # or zmq.PLAIN or zmq.CURVE

It is not the NULL special C constant.

To send an empty message, simply send an empty bytestring:

socket.send(b'')

The second point is that you need to send the empty frame as a separate message, which you are not doing. Here is a working example:

def http_hello_world():
    ctx = zmq.Context()
    sock = ctx.socket(zmq.ROUTER)
    sock.router_raw = True
    sock.bind("tcp://*:8080")
    while True:
        id_bytes, request = sock.recv_multipart()
        print("id: %r" % id_bytes)
        print("request:", request.decode('utf8'))
        if b'/close' in request:
            return

        # send the body of the response
        sock.send_multipart([
            id_bytes,
b"""HTTP/1.0 200 OK
Content-Type: text/plain

Hello, world!
"""
        ])
        # send an empty message to finish the response
        sock.send_multipart([
            id_bytes,
            b''
        ])

By the way, a comment in Github entry shows that it may not close the connection to the client even in C. How can I ask the remote client to close its connection (in Python) ?

I think, as long as you send the empty frame to terminate the message, connections should be closed.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top