diff options
| author | Hugo Lindström <hugolm84@gmail.com> | 2020-07-09 12:59:25 +0200 |
|---|---|---|
| committer | Garrett D'Amore <garrett@damore.org> | 2024-01-01 21:00:11 -0800 |
| commit | b989bedf8051b8ce3c27c4385d56239b21764700 (patch) | |
| tree | f2a6b77e44d2fda3c25e60aec28f3eea5ed64025 /demo | |
| parent | ad2d7eae574badf67c0778a5ae395d895ad07584 (diff) | |
| download | nng-b989bedf8051b8ce3c27c4385d56239b21764700.tar.gz nng-b989bedf8051b8ce3c27c4385d56239b21764700.tar.bz2 nng-b989bedf8051b8ce3c27c4385d56239b21764700.zip | |
Add a nng_stream example paired with a socket server on win/linux
Diffstat (limited to 'demo')
| -rw-r--r-- | demo/stream/CMakeLists.txt | 27 | ||||
| -rw-r--r-- | demo/stream/platform/posix/server.c | 53 | ||||
| -rw-r--r-- | demo/stream/platform/windows/server.c | 87 | ||||
| -rw-r--r-- | demo/stream/stream.c | 109 |
4 files changed, 276 insertions, 0 deletions
diff --git a/demo/stream/CMakeLists.txt b/demo/stream/CMakeLists.txt new file mode 100644 index 00000000..3b767690 --- /dev/null +++ b/demo/stream/CMakeLists.txt @@ -0,0 +1,27 @@ +# +# Copyright 2020 Hugo Lindström <hugolm84@gmail.com> +# +# This software is supplied under the terms of the MIT License, a +# copy of which should be located in the distribution where this +# file was obtained (LICENSE.txt). A copy of the license may also be +# found online at https://opensource.org/licenses/MIT. + +cmake_minimum_required (VERSION 2.8.7) + +project(stream) + +find_package(nng CONFIG REQUIRED) + +add_executable(${PROJECT_NAME}) + +target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/stream.c) + +if (CMAKE_SYSTEM_NAME MATCHES "Linux") + target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/platform/posix/server.c) +endif() + +if (CMAKE_SYSTEM_NAME MATCHES "Windows") + target_sources(${PROJECT_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/platform/windows/server.c) +endif() + +target_link_libraries(stream nng::nng) diff --git a/demo/stream/platform/posix/server.c b/demo/stream/platform/posix/server.c new file mode 100644 index 00000000..1b238f17 --- /dev/null +++ b/demo/stream/platform/posix/server.c @@ -0,0 +1,53 @@ +// Copyright 2020 Hugo Lindström <hugolm84@gmail.com> + +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. + +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <strings.h> +#include <sys/socket.h> +#include <unistd.h> + +void +error(const char *msg) +{ + perror(msg); + exit(1); +} + +int +server(int portno) +{ + int sockfd, newsockfd; + socklen_t clilen; + struct sockaddr_in serv_addr, cli_addr; + int n; + sockfd = socket(AF_INET, SOCK_STREAM, 0); + if (sockfd < 0) { + error("ERROR opening socket"); + } + bzero((char *) &serv_addr, sizeof(serv_addr)); + serv_addr.sin_family = AF_INET; + serv_addr.sin_addr.s_addr = INADDR_ANY; + serv_addr.sin_port = htons(portno); + if (bind(sockfd, (struct sockaddr *) &serv_addr, sizeof(serv_addr)) < + 0) { + error("ERROR on binding"); + } + listen(sockfd, 5); + clilen = sizeof(cli_addr); + newsockfd = accept(sockfd, (struct sockaddr *) &cli_addr, &clilen); + if (newsockfd < 0) { + error("ERROR on accept"); + } + n = write(newsockfd, "Hello Client!", 13); + if (n < 0) + error("ERROR writing to socket"); + close(newsockfd); + close(sockfd); + return 0; +} diff --git a/demo/stream/platform/windows/server.c b/demo/stream/platform/windows/server.c new file mode 100644 index 00000000..09603ebc --- /dev/null +++ b/demo/stream/platform/windows/server.c @@ -0,0 +1,87 @@ +// Copyright 2020 Hugo Lindström <hugolm84@gmail.com> + +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. + +#include <stdio.h> +#include <stdlib.h> +#include <winsock2.h> + +void +wsa_fatal(const char *func) +{ + fprintf(stderr, "%s: %d\n", func, WSAGetLastError()); + exit(1); +} + +int +server(int portno) +{ + WSADATA wsa; + SOCKET s, new_socket; + struct sockaddr_in server, client; + int c; + char * message; + + printf("Initialising Winsock...\n"); + + if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) { + wsa_fatal("Failed to call WSAStartup"); + } + + printf("Initialised WSA.\n"); + + // Create a socket + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + wsa_fatal("Could not create socket"); + } + + printf("Socket created.\n"); + + // Prepare the sockaddr_in structure + server.sin_family = AF_INET; + server.sin_addr.s_addr = INADDR_ANY; + server.sin_port = htons(portno); + + // Bind + if (bind(s, (struct sockaddr *) &server, sizeof(server)) == + SOCKET_ERROR) { + wsa_fatal("Bind failed"); + } + + printf("Bind done\n"); + + // Listen to incoming connections + listen(s, 3); + + // Accept and incoming connection + printf("Waiting for incoming connections...\n"); + + c = sizeof(struct sockaddr_in); + + while ((new_socket = accept(s, (struct sockaddr *) &client, &c)) != + INVALID_SOCKET) { + printf("Connection accepted\n"); + // Reply to the client + message = "Hello Client!"; + if (send(new_socket, message, (int) strlen(message), 0) == + SOCKET_ERROR) { + wsa_fatal("Failed to send message to client!"); + } + } + + if (new_socket == INVALID_SOCKET) { + wsa_fatal("accept failed"); + } + + if (closesocket(s) == SOCKET_ERROR) { + wsa_fatal("Failed to close socket"); + } + + if (WSACleanup() == SOCKET_ERROR) { + wsa_fatal("Failed to WSACleanup"); + } + return 0; +} diff --git a/demo/stream/stream.c b/demo/stream/stream.c new file mode 100644 index 00000000..c6cc9b23 --- /dev/null +++ b/demo/stream/stream.c @@ -0,0 +1,109 @@ +// Copyright 2020 Hugo Lindström <hugolm84@gmail.com> + +// This software is supplied under the terms of the MIT License, a +// copy of which should be located in the distribution where this +// file was obtained (LICENSE.txt). A copy of the license may also be +// found online at https://opensource.org/licenses/MIT. +// + +// This program serves as an example for how to write async communication with +// an arbitrary socket using nng_stream. The server receives a connection and +// sends a hello message to the nng_stream iov. + +// To run this program, start the server as stream -s <portnumber> +// Then connect to it with the client as stream -c <url> +// +// For example: +// +// % ./stream -s 5555 & +// % ./stream -c tcp://127.0.0.1:5555 + +#include <nng/nng.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void +nng_fatal(const char *func, int rv) +{ + fprintf(stderr, "%s: %s\n", func, nng_strerror(rv)); + exit(1); +} + +int server(int port); +int client(const char *url); + +int +main(int argc, char **argv) +{ + int rc; + + if (argc < 3) { + fprintf(stderr, "Usage: %s [-s port|-c url]\n", argv[0]); + exit(EXIT_FAILURE); + } + + if (strcmp(argv[1], "-s") == 0) { + rc = server(atoi(argv[2])); + } else { + rc = client(argv[2]); + } + exit(rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE); +} + +int +client(const char *url) +{ + nng_stream_dialer *dialer; + nng_aio * aio; + nng_iov iov; + int rv; + + // Allocatate dialer and aio assoicated with this connection + if ((rv = nng_stream_dialer_alloc(&dialer, url)) != 0) { + nng_fatal("call to nng_stream_dialer_alloc failed", rv); + } + + if ((rv = nng_aio_alloc(&aio, NULL, NULL)) != 0) { + nng_fatal("call to nng_aio_alloc", rv); + } + nng_aio_set_timeout(aio, 5000); // 5 sec + + // Allocatate a buffer to recv + iov.iov_len = 100; + iov.iov_buf = (char *) malloc(sizeof(char) * iov.iov_len); + if ((rv = nng_aio_set_iov(aio, 1, &iov)) != 0) { + nng_fatal("call to nng_aio_alloc", rv); + } + // Connect to the socket via url provided to alloc + nng_stream_dialer_dial(dialer, aio); + + // Wait for connection + nng_aio_wait(aio); + if ((rv = nng_aio_result(aio)) != 0) { + nng_fatal("waiting for ng_stream_dialer_dial failed", rv); + } + + // Get the stream (connection) at position 0 + nng_stream *c1 = (nng_stream *) nng_aio_get_output(aio, 0); + nng_stream_recv(c1, aio); + nng_aio_wait(aio); + if ((rv = nng_aio_result(aio)) != 0) { + nng_fatal("waiting for nng_stream_recv failed", rv); + } + + size_t recv_count = nng_aio_count(aio); + if (recv_count <= 0) { + nng_fatal("Recv count was 0!", NNG_ECONNABORTED); + } else { + printf("received %zu bytes, message: '%s'\n", recv_count, + (char *) iov.iov_buf); + } + + // Send ELCOSE to send/recv associated wit this stream + free(iov.iov_buf); + nng_stream_free(c1); + nng_aio_free(aio); + nng_stream_dialer_free(dialer); + return 0; +} |
