[zeromq-dev] Creating a Simple HTTP Server using zmq_msg_send and zmq_send

Goswin von Brederlow goswin-v-b at web.de
Wed Jul 9 11:14:05 CEST 2014


On Sun, Jul 06, 2014 at 08:03:11PM -0700, Satish wrote:
> Hello Programmers
> 
> 
> I am trying to get acquaint using zeromq library and am developing a 
> program provided below on this forum.
> 
> I want to use zeromq message to retrieve HTTP message and send HTTP 
> response to multiple client.
> 
> I have gone through zguide documentation but there is only a mention of 
> Multiple client connecting to zeromq broker/process via InProcess (inproc).
> 
> 
> I am deliberately not using inproc for queues purposes/ inter threading 
> messaging as I want this done via TBB queuing.
> 
> 
> However the crux of the issue I am not get the zeromq to send back a 
> response to a web-browser using zmq_send and zmq_msg_send.
> 
> I have tried using zmq_msg_send because in runtime there is a possbility of 
> have large data stream sent back to client/web browser.
> 
> I want to zmq_msg structure there is no need to specify the data 
> limitations will receiving and sending stream from and to the client.
> 
> 
> 
> How can I solve problem?
> 
> 
> Please help.
> 
> 
> Thank you.
> 
> Satish

Zmq wasn't made for this. The existance of ZMQ_STREAM sockets is more
of an ugly hack than proper design and it behaves differently from
normal zmq sockets. It's there so one can interface non-zmq stuff with
zmq, not for it's own sake. So maybe that isn't the best way to learn zmq.
 
> -----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
> 
> 
> void release(void* data, void* hint){}

What's that? It's never used.

And where are all the required "#includ" directives?

> void main(int argc, char** argv){
> 
>     void* ZMQCONTEXT = ::zmq_ctx_new();
> 
> 
>     std::istringstream &instr = std::istringstream();
> 
> 
>     zmq_msg_t message = { "" };
> 
>     int init_status = 0, multi_status = 0;
> 
> 
> 
>     zmq_pollitem_t timer[2] = { { ::zmq_socket(ZMQCONTEXT, ZMQ_STREAM), 0, 
> ZMQ_POLLIN, 0 }, { 0, 0, ZMQ_POLLOUT, 0 } };
>     int POLLED_SIZE = sizeof(timer) / sizeof(zmq_pollitem_t);
> 
>     timer[1].socket = timer[0].socket;

WTF? Why don't you poll for ZMQ_POLLIN | ZMQ_POLLOUT?

WTF2? Why poll for ZMQ_POLLOUT at all? Since polling is level
triggered that makes no sense. ZMQ_POLLOUT only makes sense
temporarily when sending out data overflows the outgoing buffers and
then only until you managed to send the pending data.
 
>     const char *tcp_desc = "tcp://*:9090";
>     ::zmq_bind(timer[0].socket, tcp_desc);
> 
>     char http_response[100] =
>         "HTTP/1.0 200 OK\r\n"
>         "Content-Type: text/plain\r\n"
>         "\r\n"
>         "Hello, World!";
>
>     int packet_size = sizeof(http_response) / sizeof(char);

Per definition sizeof(char) == 1. What you need here is

     int packet_size = sizeof(http_response) * CHAR_BIT / 8;

But if CHAR_BIT != 8 then you are screwed anyway since the http header
needs to be send as octets.
 
>     ::zmq_msg_init(&message);
> 
>     
> 
>     do
>     {
> 
>         for (int p = 0; p < POLLED_SIZE; p++){
> 
>             ::zmq_poll(&timer[p], 1, 10);
> 
>         }//for

So you wait 10ms for incoming data and then 10ms for outgoing not
being blocked. So after this loop there might or might not be incoming
data and outgoing might or might not be blocked. But maybe you waited
20ms, or not.
 
>         ::zmq_msg_recv(&message, timer[0].socket, 0);

So this will block till there actually is some incoming data.

>         while (::zmq_msg_more(&message) == 1)
>         {
>             ::zmq_msg_recv(&message, timer[0].socket, ZMQ_DONTWAIT);
> 
>         }

ZMQ_STREAM always sends data in pairs of frames. One frame for the
peer ID and one frame for the data.

Also you get connection and disconnection messages, which are
identified by having 0 bytes of data as second frame. You need to
catch (and ignore in this case) those.
 
>         std::cout << std::endl << "Size = " << ::zmq_msg_size(&message) << 
> std::endl;
>         instr.str(static_cast<char*>(zmq_msg_data(&message)));    
> ::zmq_msg_close(&message);

Who says the data is a 0 terminated C string? Zmq messages are byte
arrays of a given size that can contain 0 at any point. You are lucky
this doesn't segfault.

>         std::cout << "Data Received = " << instr.str() << std::endl;
> 
>         //send back the response
> 
> 
>         //Prefix the socket with port id
> 
>         ::zmq_send(timer[0].socket, instr.str().c_str(), 
> instr.str().size(), ZMQ_SNDMORE);
> 
> 
>         //Send payload
>         ::zmq_send(timer[0].socket, http_response, packet_size, 
> ZMQ_SNDMORE);
> 
>         //Postfix the socket with port id
>         ::zmq_send(timer[0].socket, instr.str().c_str(), 
> instr.str().size(), ZMQ_SNDMORE);

WTF? Postfix? There is no postfix. You are starting a new message there.

>         ::zmq_send(timer[0].socket, 0, 0, ZMQ_SNDMORE);

Ahh, you mean that you close the connection to the pear.
 
>         std::cout << "Sending..." << http_response;
> 
>     } while (std::cin.get() == 0xd);
> 
> 
>     
>     for (int p = 0; p < POLLED_SIZE; p++){
> 
>         ::zmq_unbind(timer[p].socket, tcp_desc);
>         ::zmq_close(timer[p].socket);
>     }

Since both timer[p] are the same socket you are unbinding and closing
the same socket twice.
 
>     ::zmq_ctx_shutdown(&ZMQCONTEXT);    ::zmq_ctx_term(&ZMQCONTEXT);

I think shutdown belonges before the closing of sockets if used at all.

>     std::cin.get();
> 
> }


Overall I would expect your code to eigther segfault or send 3
responces for every request, two of which would go into nirvana since
you already closed the connection after the first one.

MfG
	Goswin



More information about the zeromq-dev mailing list