From 51df7f5d1b838dc9a82006e153057e3ad24b0e4a Mon Sep 17 00:00:00 2001 From: huangminhang Date: Wed, 2 Mar 2022 17:16:25 +0800 Subject: [PATCH] Add linux websocket server cpp example --- examples/linux_ws_server_cpp/CMakeLists.txt | 24 ++++ examples/linux_ws_server_cpp/README.md | 17 +++ examples/linux_ws_server_cpp/main.cc | 150 ++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 examples/linux_ws_server_cpp/CMakeLists.txt create mode 100644 examples/linux_ws_server_cpp/README.md create mode 100644 examples/linux_ws_server_cpp/main.cc diff --git a/examples/linux_ws_server_cpp/CMakeLists.txt b/examples/linux_ws_server_cpp/CMakeLists.txt new file mode 100644 index 000000000..6a71798e5 --- /dev/null +++ b/examples/linux_ws_server_cpp/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.5.1) +project(linux_ws_server) + +set(TARGET_NAME ${PROJECT_NAME}) +set(CMAKE_CXX_STANDARD 14) + +find_package(PkgConfig REQUIRED) +find_package(civetweb) + + +include_directories( + ${civetweb_INCLUDE_DIR} +) + +link_directories ( + /usr/local/lib +) + +add_executable(${TARGET_NAME} main.cc) + +target_link_libraries(${TARGET_NAME} + libcivetweb-cpp.so + libcivetweb.so +) diff --git a/examples/linux_ws_server_cpp/README.md b/examples/linux_ws_server_cpp/README.md new file mode 100644 index 000000000..662d7845d --- /dev/null +++ b/examples/linux_ws_server_cpp/README.md @@ -0,0 +1,17 @@ +[TOC] + +# Civetweb websocket cpp + +## #1 Installation + +```shell +git clone https://github.com/civetweb/civetweb.git +mkdir buildx && cd buildx +cmake -DBUILD_SHARED_LIBS=ON -DCIVETWEB_ENABLE_WEBSOCKETS=ON -DCIVETWEB_ENABLE_CXX=ON .. +make +sudo make install +``` + + + + diff --git a/examples/linux_ws_server_cpp/main.cc b/examples/linux_ws_server_cpp/main.cc new file mode 100644 index 000000000..faf477f59 --- /dev/null +++ b/examples/linux_ws_server_cpp/main.cc @@ -0,0 +1,150 @@ +#include +#include +#include +#include +#include +#include + +#include "CivetServer.h" + +class WebSocketBase : public CivetWebSocketHandler +{ + + public: + explicit WebSocketBase(std::string name) : name_(std::move(name)) + { + } + + bool + handleConnection(CivetServer *server, const mg_connection *conn) override + { + return true; + } + + void + handleReadyState(CivetServer *server, mg_connection *conn) override + { + std::unique_lock lock(mutex_); + pool_.emplace(conn, std::make_shared()); + } + + bool + handleData(CivetServer *server, + mg_connection *conn, + int bits, + char *data, + size_t data_len) override + { + + if ((bits & 0x0F) == MG_WEBSOCKET_OPCODE_CONNECTION_CLOSE) { + return false; + } + data_.write(data, data_len); + if (current_opcode_ == 0x00) { + current_opcode_ = bits & 0x7f; + } + bool is_final_fragment = bits & 0x80; + if (is_final_fragment) { + switch (current_opcode_) { + case MG_WEBSOCKET_OPCODE_TEXT: + std::cout << data_.str() << std::endl; // print request data + break; + default: + break; + } + current_opcode_ = 0x00; + this->sendData(conn, data_.str()); // response + data_.clear(); + data_.str(std::string()); + } + return true; + } + + void + handleClose(CivetServer *server, const mg_connection *conn) override + { + auto *connection = const_cast(conn); + std::shared_ptr user_lock; + { + std::unique_lock lock(mutex_); + user_lock = pool_[connection]; + } + { + std::unique_lock lock_connection(*user_lock); + std::unique_lock lock(mutex_); + pool_.erase(connection); + } + } + + bool + sendData(mg_connection *conn, + const std::string &data, + bool skippable = false, + int op_code = MG_WEBSOCKET_OPCODE_TEXT) + { + std::shared_ptr connection_lock; + { + std::unique_lock lock(mutex_); + connection_lock = pool_[conn]; + } + + if (!connection_lock->try_lock()) { + if (skippable) { + return false; + } + connection_lock->lock(); + std::unique_lock lock(mutex_); + } + + int ret = mg_websocket_write(conn, op_code, data.c_str(), data.size()); + connection_lock->unlock(); + + if (ret != static_cast(data.size())) { + if (data.empty() && ret == 2) { + return true; + } + return false; + } + + return true; + } + + thread_local static std::stringstream data_; + thread_local static unsigned char current_opcode_; + + private: + const std::string name_; + mutable std::mutex mutex_; + std::unordered_map> pool_; +}; + +thread_local unsigned char WebSocketBase::current_opcode_ = 0x00; +thread_local std::stringstream WebSocketBase::data_; + +int +main() +{ + std::cout << "Hello, Civetweb Websocket port:8080!" << std::endl; + + mg_init_library(0); + std::vector options = { + "document_root", + ".", + "listening_ports", + "8080", + "access_control_allow_headers", + "*", + "access_control_allow_methods", + "*", + "access_control_allow_origin", + "*", + }; + auto server = std::make_shared(options); + auto ws = std::make_shared("simple"); + server->addWebSocketHandler("/ws", *ws); + while (true) { + sleep(1); + } + server->close(); + return 0; +}