123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210 |
- /*
- Copyright 2016 Garrett D'Amore <garrett@damore.org>
- Permission is hereby granted, free of charge, to any person obtaining a copy
- of this software and associated documentation files (the "Software"),
- to deal in the Software without restriction, including without limitation
- the rights to use, copy, modify, merge, publish, distribute, sublicense,
- and/or sell copies of the Software, and to permit persons to whom
- the Software is furnished to do so, subject to the following conditions:
- The above copyright notice and this permission notice shall be included
- in all copies or substantial portions of the Software.
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- IN THE SOFTWARE.
- "nanomsg" is a trademark of Martin Sustrik
- */
- /* This program serves as an example for how to write a simple RPC service,
- using the request/reply pattern. The server is just a single threaded
- for loop, which processes each request. The requests run quickly enough
- that there is no need for parallelism.
- Our demonstration application layer protocol is simple. The client sends
- a name, and the server replies with a greeting based on the time of day.
- The messages are sent in ASCII, and are not zero terminated.
- To run this program, start the server as rpc_demo <url> -s
- Then connect to it with the client as rpc_client <url> <name>.
- The client will print a timezone appropriate greeting, based on
- the time at the server. For example:
- % ./rpc_demo tcp://127.0.0.1:5555 -s &
- % ./rpc_demo tcp://127.0.0.1:5555 Garrett
- Good morning, Garrett.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <time.h>
- #include <nanomsg/nn.h>
- #include <nanomsg/reqrep.h>
- /* The server runs forever. */
- int server(const char *url)
- {
- int fd;
- /* Create the socket. */
- fd = nn_socket (AF_SP, NN_REP);
- if (fd < 0) {
- fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ()));
- return (-1);
- }
- /* Bind to the URL. This will bind to the address and listen
- synchronously; new clients will be accepted asynchronously
- without further action from the calling program. */
- if (nn_bind (fd, url) < 0) {
- fprintf (stderr, "nn_bind: %s\n", nn_strerror (nn_errno ()));
- nn_close (fd);
- return (-1);
- }
- /* Now we can just process results. Note that there is no explicit
- accept required. We just receive a request, and reply to it.
- Its important to note that we must not issue two receives in a
- row without replying first, or the following receive(s) will
- cancel any unreplied requests. */
- for (;;) {
- char username[128];
- char greeting[128];
- time_t secs;
- struct tm *now;
- char *daytime;
- int rc;
- char *fmt;
- rc = nn_recv (fd, username, sizeof (username), 0);
- if (rc < 0) {
- /* Any error here is unexpected. */
- fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ()));
- break;
- }
- secs = time (NULL);
- now = localtime (&secs);
- if (now->tm_hour < 12) {
- daytime = "morning";
- } else if (now->tm_hour < 17) {
- daytime = "afternoon";
- } else if (now->tm_hour < 20) {
- daytime = "evening";
- } else {
- daytime = "night";
- }
- /* Ensure ASCIIZ terminated string. */
- if (rc < sizeof (username)) {
- username[rc] = '\0';
- } else {
- username[sizeof (username) - 1] = '\0';
- }
- fmt = "Good %s, %s.";
- /* Technically this might be overly pessimistic about size. */
- if ((strlen (username) + strlen (daytime) + strlen (fmt)) >=
- sizeof (greeting)) {
- fmt = "I'm sorry, your name is too long. But good %s anyway.";
- }
- /* snprintf would be safer, but the above check protects us. */
- sprintf (greeting, fmt, daytime, username);
- rc = nn_send (fd, greeting, strlen (greeting), 0);
- if (rc < 0) {
- /* There are several legitimate reasons this can fail.
- We note them for debugging purposes, but then ignore
- otherwise. If the socket is closed or failing, we will
- notice in recv above, and exit then. */
- fprintf (stderr, "nn_send: %s (ignoring)\n",
- nn_strerror (nn_errno ()));
- }
- }
- nn_close (fd);
- return (-1);
- }
- /* The client runs just once, and then returns. */
- int client (const char *url, const char *username)
- {
- int fd;
- int rc;
- char *greeting;
- char *msg;
- fd = nn_socket (AF_SP, NN_REQ);
- if (fd < 0) {
- fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ()));
- return (-1);
- }
- if (nn_connect (fd, url) < 0) {
- fprintf (stderr, "nn_socket: %s\n", nn_strerror (nn_errno ()));
- nn_close (fd);
- return (-1);
- }
- if (nn_send (fd, username, strlen (username), 0) < 0) {
- fprintf (stderr, "nn_send: %s\n", nn_strerror (nn_errno ()));
- nn_close (fd);
- return (-1);
- }
- /* Here we ask the library to allocate response buffer for us (NN_MSG). */
- rc = nn_recv (fd, &msg, NN_MSG, 0);
- if (rc < 0) {
- fprintf (stderr, "nn_recv: %s\n", nn_strerror (nn_errno ()));
- nn_close (fd);
- return (-1);
- }
- nn_close (fd);
- /* Response is not ASCIIZ terminated. */
- greeting = malloc (rc + 1);
- if (greeting == NULL) {
- fprintf (stderr, "malloc: %s\n", strerror (errno));
- return (-1);
- }
- memcpy(greeting, msg, rc);
- greeting[rc] = '\0';
- nn_freemsg (msg);
- printf ("%s\n", greeting);
- free(greeting);
- return (0);
- }
- int main (int argc, char **argv)
- {
- int rc;
- if (argc < 3) {
- fprintf (stderr, "Usage: %s <url> [-s|name]\n", argv[0]);
- exit (EXIT_FAILURE);
- }
- if (strcmp (argv[2], "-s") == 0) {
- rc = server (argv[1]);
- } else {
- rc = client (argv[1], argv[2]);
- }
- exit (rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE);
- }
|