简单的websocket_server.cc

简单的websocket_server.cc

参考的wenet/runtime/里websocker_server_main的写法,里面用了boost库进行websocket。进行语音识别,我这里把代码抠出来,只要websocket通信功能,后续开发什么功能(比如例子的语音识别)都可以。

命令行敲 tree -L 2 . , 查看二级目录

这里一开始只要新建yl_websocket_server.cc、yl_websocket_server.h、cmake里的boost.cmake、CMakeLists.txt就行,其它的(build/和fc_base文件夹)都是后续生成的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.
├── CMakeLists.txt
├── build
│ ├── CMakeCache.txt
│ ├── CMakeFiles
│ ├── Makefile
│ ├── cmake_install.cmake
│ ├── yl_websocket_client_main
│ └── yl_websocket_server_main
├── cmake
│ └── boost.cmake
├── fc_base
│ ├── boost-build
│ ├── boost-src
│ ├── boost-subbuild
│ └── ex-boost-populate1234
├── yl_websocket_client.cc
├── yl_websocket_client.h
├── yl_websocket_server.cc
└── yl_websocket_server.h

其中几个文件内容:

yl_websocket_server.cc:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
#include "yl_websocket_server.h"
#include <iostream>
#include "boost/json/src.hpp"
#include <thread>
#include <utility>
#include <vector>

namespace beast = boost::beast; // from <boost/beast.hpp>
namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace asio = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>
namespace json = boost::json;


ConnectionHandler::ConnectionHandler(tcp::socket&& socket): ws_(std::move(socket)) {}

void ConnectionHandler::operator()() {
try {
// Accept the websocket handshake
ws_.accept();
for (;;) {
// This buffer will hold the incoming message
beast::flat_buffer buffer;
// Read a message
ws_.read(buffer); //看ws_读数据,也就是先有client给ws_写了东西
if (ws_.got_text()) {
std::string message = beast::buffers_to_string(buffer.data());
std::cout << message << std::endl;
std::string backmessage = "success";
ws_.text(true);
ws_.write(asio::buffer(backmessage)); // 写给client
break;
}
else {
break;
}
}
} catch (beast::system_error const& se) {
// LOG(INFO) << se.code().message();
std::cout << se.code().message();
// This indicates that the session was closed
if (se.code() == websocket::error::closed) {
// OnSpeechEnd();
}
// if (decode_thread_ != nullptr) {
// decode_thread_->join();
// }
} catch (std::exception const& e) {
// LOG(ERROR) << e.what();
std::cout << e.what();
}
}



void WebSocketServer::Start(){
try{
auto const address = asio::ip::make_address("0.0.0.0");
tcp::acceptor acceptor{ioc_, {address, static_cast<uint16_t>(port_)}};
// 一直在循环执行
for (;;) {
// This will receive the new connection
tcp::socket socket{ioc_};
std::cout << "wait message" << std::endl;
// Block until we get a connection
acceptor.accept(socket); // 接受客户端连接请求,在这里地方就停住了,直到客户端有请求,程序才接着往下走。
std::cout << "receive" << std::endl;
// Launch the session, transferring ownership of the socket
ConnectionHandler handler(std::move(socket));
std::thread t(std::move(handler)); // 在子线程中 进入operator函数
t.detach();
}
} catch (const std::exception& e) {
std::cout << e.what();
// LOG(ERROR) << e.what();
}
}

int main(){
WebSocketServer server(10021);
server.Start();
return 0;
}

yl_websocket_server.h:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#ifndef WEBSOCKET_WEBSOCKET_SERVER_H_
#define WEBSOCKET_WEBSOCKET_SERVER_H_

#include <iostream>
#include <memory>
#include <string>
#include <thread>
#include <utility>

#include "boost/asio/connect.hpp"
#include "boost/asio/ip/tcp.hpp"
#include "boost/beast/core.hpp"
#include "boost/beast/websocket.hpp"

namespace beast = boost::beast; // from <boost/beast.hpp>
// namespace http = beast::http; // from <boost/beast/http.hpp>
namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp>
namespace asio = boost::asio; // from <boost/asio.hpp>
using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>


class ConnectionHandler {
public:
ConnectionHandler(tcp::socket&& socket);
void operator()();

private:
websocket::stream<tcp::socket> ws_;

bool got_start_tag_ = false;
bool got_end_tag_ = false;
// When endpoint is detected, stop recognition, and stop receiving data.
bool stop_recognition_ = false;

};





class WebSocketServer{
public:
WebSocketServer(int port):port_(port){}
void Start();
private:
int port_;
asio::io_context ioc_{1};
};

#endif // WEBSOCKET_WEBSOCKET_SERVER_H_

cmake/boost.cmake

1
2
3
4
5
6
7
8
9
FetchContent_Declare(boost
URL https://boostorg.jfrog.io/artifactory/main/release/1.75.0/source/boost_1_75_0.tar.gz
URL_HASH SHA256=aeb26f80e80945e82ee93e5939baebdca47b9dee80a07d3144be1e1a6a66dd6a
)
FetchContent_MakeAvailable(boost)
include_directories(${boost_SOURCE_DIR})

if(MSVC)
add_definitions(-DBOOST_ALL_DYN_LINK -DBOOST_ALL_NO_LIB)

这个会自动下载boost包

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
cmake_minimum_required(VERSION 3.14 FATAL_ERROR)

project (websockettest)

# SET(CMAKE_BUILD_TYPE "Debug")
# SET(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb")
# SET(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAGS} -O3 -Wall")


set(CMAKE_VERBOSE_MAKEFILE OFF)



include(FetchContent)
set(FETCHCONTENT_QUIET OFF)
get_filename_component(fc_base "fc_base" REALPATH BASE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(FETCHCONTENT_BASE_DIR ${fc_base})

list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
# target_link_libraries(yl_websocket_server_main PUBLIC websocket)

if(NOT MSVC)
# Keep the same with openfst, -fPIC or -fpic
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -pthread -fPIC")
else()
set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON)
add_compile_options("$<$<CXX_COMPILER_ID:MSVC>:/utf-8>")
endif()

include(boost)

# aux_source_directory(. DIR_LIB_SRCS)
# add_executable(yl_websocket_server_main ${DIR_LIB_SRCS})

add_executable(yl_websocket_server_main yl_websocket_server.cc)
add_executable(yl_websocket_client_main yl_websocket_client.cc)

然后在命令行里敲:

1
2
3
4
mkdir build
cd build
cmake ..
cmake --build .

就可以在build/里看见名叫yl_websocket_server的可执行文件了。