From 206e421728ac923281c7cca79ff4e55487e63ce7 Mon Sep 17 00:00:00 2001 From: Unknown Date: Sat, 3 Mar 2018 16:08:42 +0000 Subject: [PATCH] Actually pushed across examples --- .../CMakeLists.txt | 8 ++ .../SimpleWebsocketClient.cpp | 84 ++++++++++++++++ .../SimpleWebsocketServer.cpp | 98 +++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 examples/simple_websocket_server_and_client/CMakeLists.txt create mode 100644 examples/simple_websocket_server_and_client/SimpleWebsocketClient.cpp create mode 100644 examples/simple_websocket_server_and_client/SimpleWebsocketServer.cpp diff --git a/examples/simple_websocket_server_and_client/CMakeLists.txt b/examples/simple_websocket_server_and_client/CMakeLists.txt new file mode 100644 index 0000000..e0f89e1 --- /dev/null +++ b/examples/simple_websocket_server_and_client/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(simple_websocket_client SimpleWebsocketClient.cpp) +target_link_libraries(simple_websocket_client frnetlib) + +add_executable(simple_websocket_server SimpleWebsocketServer.cpp) +target_link_libraries(simple_websocket_server frnetlib) + +install(TARGETS simple_websocket_client simple_websocket_server + DESTINATION "bin") diff --git a/examples/simple_websocket_server_and_client/SimpleWebsocketClient.cpp b/examples/simple_websocket_server_and_client/SimpleWebsocketClient.cpp new file mode 100644 index 0000000..3c42950 --- /dev/null +++ b/examples/simple_websocket_server_and_client/SimpleWebsocketClient.cpp @@ -0,0 +1,84 @@ +// +// Created by fred on 02/03/18. +// + +#include +#include +#include +#include +#include + +int main() +{ + //Connect to the WebSocket server + fr::WebSocket socket; //Use an fr::SSLSocket for secure connections + if(socket.connect("127.0.0.1", "9091", {}) != fr::Socket::Success) + { + std::cerr << "Failed to connect to server!" << std::endl; + return EXIT_FAILURE; + } + + //Loop to send messages. Not ideal due to a lack of locking, but should be okay for an example. + auto message_loop = [&socket]() { + std::string message; + fr::WebFrame frame; + while(socket.connected()) + { + std::cout << "Message: " << std::endl; + std::getline(std::cin, message); + if(message == "exit") + { + socket.disconnect(); + return; + } + else if(message == "ping") + { + frame.set_opcode(fr::WebFrame::Ping); + } + frame.set_payload(std::move(message)); + socket.send(frame); + message.clear(); //Returns message to a defined state after the std::move + } + }; + std::thread t1(message_loop); + + //Put the socket into non-blocking mode, for dealing with PINGs and whatnot without waiting. + while(socket.connected()) + { + //Receive the next frame + fr::WebFrame frame; + if(socket.receive(frame) != fr::Socket::Success) + continue; + + //If it's a Ping then we need to send back a frame containing the same payload, but of type Pong. + if(frame.get_opcode() == fr::WebFrame::Ping) + { + std::cout << "Server sent a ping!" << std::endl; + frame.set_opcode(fr::WebFrame::Pong); + socket.send(frame); + continue; + } + + //If it's a disconnect message, then we should finish sending across any messages, and then call disconnect + if(frame.get_opcode() == fr::WebFrame::Disconnect) + { + socket.disconnect(); + continue; + } + + //The payload type could be Text, Binary, or Continuation. + //If it's Continuation, then this frame is a part of a fragmented message, and it's + //a continuation from a previous message. You can check if it's the final part of the + //message using fr::WebFrame::is_final(). + std::cout << "Got a new message from the server. It's a "; + if(frame.get_opcode() == fr::WebFrame::Text) std::cout << "text"; + else if(frame.get_opcode() == fr::WebFrame::Binary) std::cout << "binary"; + else if(frame.get_opcode() == fr::WebFrame::Pong) std::cout << "pong"; + else std::cout << "continuation of a previous"; + std::cout << " message. It is "; + if(!frame.is_final()) std::cout << "not "; + std::cout << "the final part of the message. The payload contains: '" << frame.get_payload() << "'." << std::endl; + } + std::cout << "The server disconnected!" << std::endl; + t1.join(); +} \ No newline at end of file diff --git a/examples/simple_websocket_server_and_client/SimpleWebsocketServer.cpp b/examples/simple_websocket_server_and_client/SimpleWebsocketServer.cpp new file mode 100644 index 0000000..a1da89f --- /dev/null +++ b/examples/simple_websocket_server_and_client/SimpleWebsocketServer.cpp @@ -0,0 +1,98 @@ +// +// Created by fred on 02/03/18. +// + +#include +#include +#include +#include +#include + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wmissing-noreturn" +int main() +{ + //Bind to port, fr::SSLListener should be used for TLS connections + fr::TcpListener listener; + if(listener.listen("9091") != fr::Socket::Success) + { + std::cerr << "Failed to bind to port!" << std::endl; + return EXIT_FAILURE; + } + + //Use fr::WebSocket if using an SSL listener + fr::WebSocket socket; + + //Loop to send messages. Not ideal due to a lack of locking, but should be okay for an example. + auto message_loop = [&socket]() { + std::string message; + fr::WebFrame frame; + while(true) + { + frame.set_opcode(fr::WebFrame::Text); + std::cout << "Message: " << std::endl; + std::getline(std::cin, message); + if(message == "exit") + { + socket.disconnect(); + return; + } + else if(message == "ping") + { + frame.set_opcode(fr::WebFrame::Ping); + } + frame.set_payload(std::move(message)); + socket.send(frame); + message.clear(); //Returns message to a defined state after the std::move + } + }; + std::thread t1(message_loop); + + while(true) + { + //Accept a new WebSocket connection. + if(listener.accept(socket) != fr::Socket::Success) + continue; + std::cout << "Accepted new connection: " << socket.get_remote_address() << std::endl; + + //Whilst we remain connected, keep processing messages + while(socket.connected()) + { + //Receive the next frame + fr::WebFrame frame; + if(socket.receive(frame) != fr::Socket::Success) + continue; + + //If it's a Ping then we need to send back a frame containing the same payload, but of type Pong. + if(frame.get_opcode() == fr::WebFrame::Ping) + { + std::cout << "Client sent a ping!" << std::endl; + frame.set_opcode(fr::WebFrame::Pong); + socket.send(frame); + continue; + } + + //If it's a disconnect message, then we should finish sending across any messages, and then call disconnect + if(frame.get_opcode() == fr::WebFrame::Disconnect) + { + socket.disconnect(); + continue; + } + + //The payload type could be Text, Binary, or Continuation. + //If it's Continuation, then this frame is a part of a fragmented message, and it's + //a continuation from a previous message. You can check if it's the final part of the + //message using fr::WebFrame::is_final(). + std::cout << "Got a new message from the client. It's a "; + if(frame.get_opcode() == fr::WebFrame::Text) std::cout << "text"; + else if(frame.get_opcode() == fr::WebFrame::Binary) std::cout << "binary"; + else if(frame.get_opcode() == fr::WebFrame::Pong) std::cout << "pong"; + else std::cout << "continuation of a previous"; + std::cout << " message. It is "; + if(!frame.is_final()) std::cout << "not "; + std::cout << "the final part of the message. The payload contains: '" << frame.get_payload() << "'." << std::endl; + } + std::cout << socket.get_remote_address() << " disconnected!" << std::endl; + } +} +#pragma clang diagnostic pop \ No newline at end of file