Explorar el Código

Add linux websocket server cpp example

huangminhang hace 3 años
padre
commit
51df7f5d1b

+ 24 - 0
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
+)

+ 17 - 0
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
+```
+
+
+
+

+ 150 - 0
examples/linux_ws_server_cpp/main.cc

@@ -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;
+}