Skip to content
This repository has been archived by the owner on Nov 5, 2023. It is now read-only.

Commit

Permalink
Merge pull request civetweb#1059 from minhanghuang/linux-ws-cpp
Browse files Browse the repository at this point in the history
Add websocket server cpp example
  • Loading branch information
bel2125 authored May 23, 2022
2 parents 9166d50 + 51df7f5 commit 4447b65
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 0 deletions.
24 changes: 24 additions & 0 deletions examples/linux_ws_server_cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
17 changes: 17 additions & 0 deletions examples/linux_ws_server_cpp/README.md
Original file line number Diff line number Diff line change
@@ -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
```




150 changes: 150 additions & 0 deletions examples/linux_ws_server_cpp/main.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
#include <iostream>
#include <memory>
#include <mutex>
#include <sstream>
#include <unistd.h>
#include <unordered_map>

#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<std::mutex> lock(mutex_);
pool_.emplace(conn, std::make_shared<std::mutex>());
}

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<mg_connection *>(conn);
std::shared_ptr<std::mutex> user_lock;
{
std::unique_lock<std::mutex> lock(mutex_);
user_lock = pool_[connection];
}
{
std::unique_lock<std::mutex> lock_connection(*user_lock);
std::unique_lock<std::mutex> 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<std::mutex> connection_lock;
{
std::unique_lock<std::mutex> lock(mutex_);
connection_lock = pool_[conn];
}

if (!connection_lock->try_lock()) {
if (skippable) {
return false;
}
connection_lock->lock();
std::unique_lock<std::mutex> lock(mutex_);
}

int ret = mg_websocket_write(conn, op_code, data.c_str(), data.size());
connection_lock->unlock();

if (ret != static_cast<int>(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<mg_connection *, std::shared_ptr<std::mutex>> 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<std::string> options = {
"document_root",
".",
"listening_ports",
"8080",
"access_control_allow_headers",
"*",
"access_control_allow_methods",
"*",
"access_control_allow_origin",
"*",
};
auto server = std::make_shared<CivetServer>(options);
auto ws = std::make_shared<WebSocketBase>("simple");
server->addWebSocketHandler("/ws", *ws);
while (true) {
sleep(1);
}
server->close();
return 0;
}

0 comments on commit 4447b65

Please sign in to comment.