{"id":843,"date":"2021-04-12T07:27:34","date_gmt":"2021-04-12T01:57:34","guid":{"rendered":"https:\/\/cenacle.io\/?p=639"},"modified":"2021-04-12T07:27:34","modified_gmt":"2021-04-12T01:57:34","slug":"combining-zeromq-and-nanomsg-for-serving-web-requests","status":"publish","type":"post","link":"https:\/\/gk.palem.in\/articles\/combining-zeromq-and-nanomsg-for-serving-web-requests\/","title":{"rendered":"Combining ZeroMQ and NanoMsg for Serving Web-requests"},"content":{"rendered":"\n<p>Web-requests typically follow a request-reply pattern. However, ZeroMQ has severe restrictions on using REQ-REP patterns in an asynchronous way.<\/p>\n\n\n\n<p>NanoMsg attempts to solve this strictness of REQ-REP by fusing them with reconnect capabilities and load-balancing features. While this is good, and in some sense try to mimic the behavior of DEALER-ROUTER combination of ZMQ, they are not compatible with raw BSD sockets to be able to let web-browsers talk to them directly.<\/p>\n\n\n\n<p>ZeroMQ on the otherhand offers RAW ROUTER capabilites that lets browsers talk to them natively in HTTP.<\/p>\n\n\n\n<p>And you can take advantage of both of these message frameworks to get the advantage of raw http compatibility (with raw ROUTER socket of ZMQ on the front) and unrestricted request-response patter on NanoMsg in the backend.<\/p>\n\n\n\n<p>Here is the basic version of fusing the ZMQ raw ROUTER (frontend) socket and NanoMsg REQ-REP (backend) sockets.<\/p>\n\n\n\n<pre class=\"wp-block-code\"><code>#include \"czmq.h\"\n#include \"nn.h\"\n#include \"reqrep.h\"\n\n#define WORKER_SOCKET_ADDRESS \"inproc:\/\/test\"\n\nvoid* nano_worker(void* args)\n{\n    int rc;\n    int workerSock;\n    char request&#91;4096];\n    char response&#91;] = \"HTTP \/ 1.0 200 OK\\r\\nContent - Type: text \/ plain\\r\\n\\r\\nHello World!!\";\n    int nResponseLen = strlen(response);\n\n    workerSock = nn_socket(AF_SP, NN_REP);\n    assert(workerSock &gt;= 0);\n    nn_bind(workerSock, WORKER_SOCKET_ADDRESS);\n    int i = 0;\n    while (1)\n    {\n        rc = nn_recv(workerSock, request, sizeof (request), 0);\n        assert(rc &gt;= 0);\n\n        rc = nn_send(workerSock, response, nResponseLen+1, 0);\n        assert(rc &gt;= 0);\n    }\n}\n\nint main(void)\n{\n    zctx_t *ctx = zctx_new();\n    void *router = zsocket_new(ctx, ZMQ_ROUTER);\n    zsocket_set_router_raw(router, 1);\n    zsocket_set_sndhwm(router, 0);\n    zsocket_set_rcvhwm(router, 0);\n    int rc = zsocket_bind(router, \"tcp:\/\/*:8080\");\n    assert(rc != -1);\n\n    zthread_new(nano_worker, NULL);\n\n    int sock = nn_socket(AF_SP, NN_REQ);\n    assert(sock &gt;= 0);\n    assert(nn_connect(sock, WORKER_SOCKET_ADDRESS) &gt;= 0);\n\n    while (true)\n    {\n        \/\/  Get HTTP request\n        zframe_t *identity = zframe_recv(router);\n        if (!identity) break;          \/\/  Ctrl-C interrupt\n        char *request = zstr_recv(router);\n        {\n            \/\/ forward the http-request to NanoMsg\n            int bytes = nn_send(sock, request, strlen(request), 0);\n            assert(bytes &gt;= 0);\n        }\n        free(request);     \/\/ free the memory\n\n        \/\/ read the response from NanoMsg worker\n        char* response = NULL;\n        int bytes = nn_recv(sock, &amp;response, NN_MSG, 0);\n        assert(bytes &gt;= 0);\n        {\n            \/\/  Send response to client\/browser\n            zframe_send(&amp;identity, router, ZFRAME_MORE + ZFRAME_REUSE);\n            zstr_send(router, response);\n\n            \/\/  Close connection to browser\n            zframe_send(&amp;identity, router, ZFRAME_MORE);\n            zmq_send(router, NULL, 0, 0);\n        }\n        nn_freemsg(response); \/\/ free the memory\n    }\n    zctx_destroy(&amp;ctx);\n    return 0;\n}\n<\/code><\/pre>\n\n\n\n<p>A pretty simple example, that always replies &#8216;Hello World!!&#8217; to the browser. The raw ROUTER socket is listening on TCP port 8080, so any browser that sends a request on port 8080 of localhost, will get back the response. The internal <em>NanoMsg <\/em>communication is happening on <em>inproc <\/em>channel. A dedicated thread is created for the <em>NanoMsg <\/em>worker socket (REP) that serves the responses. You can experiment with creating multiple <em><em>NanoMsg<\/em><\/em> worker threads and stress testing. it.<\/p>\n\n\n\n<p>If interested in learning more designing distributed architectures using advanced network and message frameworks, you may find our Live-Project Trainings useful. Please <a rel=\"noreferrer noopener\" href=\"https:\/\/cenacle.io\/blog\/apply-for-live-projects-training-597\/\" data-type=\"URL\" data-id=\"https:\/\/cenacle.io\/blog\/apply-for-live-projects-training-597\/\" target=\"_blank\">Apply here<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Web-requests typically follow a request-reply pattern. However, ZeroMQ has severe restrictions on using REQ-REP patterns in an asynchronous way.  NanoMsg attempts to solve this strictness of REQ-REP by fusing them with reconnect capabilities and load-balancing features. <\/p>\n","protected":false},"author":1,"featured_media":848,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"advanced_seo_description":"","jetpack_seo_html_title":"","jetpack_seo_noindex":false,"jetpack_post_was_ever_published":false,"_cloudinary_featured_overwrite":false,"fifu_image_url":"https:\/\/res.cloudinary.com\/cenacle-cdn\/image\/upload\/v1618192548\/CenacleResearch\/blog\/images\/Router-Connections.jpg","fifu_image_alt":"Combining ZeroMQ and NanoMsg for Serving Web-requests","footnotes":""},"categories":[69],"tags":[81,82],"class_list":["post-843","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-blog","tag-distributed-architecture","tag-programming"],"jetpack_featured_media_url":"https:\/\/res.cloudinary.com\/cenacle-cdn\/images\/v1715779375\/gk.palem.in\/wp_assets\/Router-Connections\/Router-Connections.jpg?_i=AA","jetpack-related-posts":[],"jetpack_shortlink":"https:\/\/wp.me\/pfLaRd-dB","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/posts\/843","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/comments?post=843"}],"version-history":[{"count":0,"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/posts\/843\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/media\/848"}],"wp:attachment":[{"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/media?parent=843"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/categories?post=843"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gk.palem.in\/articles\/wp-json\/wp\/v2\/tags?post=843"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}