Boost Beast 异步 Websocket 服务器 如何与会话交互?

2023-12-29

所以我不知道为什么,但我无法理解 boost Beast websocket 服务器以及如何(或应该)与其交互。

我制作的基本程序看起来像这样,跨 2 个类(WebSocketListener and WebSocketSession) https://www.boost.org/doc/libs/develop/libs/beast/example/websocket/server/async/websocket_server_async.cpp https://www.boost.org/doc/libs/develop/libs/beast/example/websocket/server/async/websocket_server_async.cpp

一切都很好,我可以连接,并且它会回显消息。我们只会有 1 个活动会话,并且我正在努力理解如何从其类外部(例如在我的 int main() 或另一个可能负责发出读/写的类中)与该会话进行交互。我们将使用一个简单的命令设计模式,命令异步进入缓冲区,针对硬件进行处理,然后 async_write 返回结果。读取和排队是直接的,将在WebsocketSession,但我看到的所有写入都只是直接在会话内读取/写入,而不是获取外部输入。

我见过使用类似的例子boost::asio::async_write(socket, buffer, ...)但我很难理解当侦听器本身创建会话时如何获取对所述套接字的引用。


我不依赖会话外部的套接字,而是取决于你的程序逻辑来实施会议。

这是因为会话(连接)将管理其自己的生命周期,自发到达并可能自发断开。您的硬件很可能没有。

因此,借用“依赖注入”的概念告诉您的侦听器您的应用程序逻辑,然后从会话中调用该逻辑。 (侦听器会将依赖项“注入”到每个新创建的会话中)。

让我们从链接示例的简化/现代化版本开始。

现在,在我们准备响应的地方,您希望注入自己的逻辑,所以让我们按照我们的想象来编写它:

void on_read(beast::error_code ec, std::size_t /*bytes_transferred*/) {
    if (ec == websocket::error::closed) return;
    if (ec.failed())                    return fail(ec, "read");

    // Process the message
    response_ = logic_->Process(beast::buffers_to_string(buffer_));

    ws_.async_write(
        net::buffer(response_),
        beast::bind_front_handler(&session::on_write, shared_from_this()));
}

这里我们声明成员并从构造函数初始化它们:

    std::string                          response_;
    std::shared_ptr<AppDomain::Logic>    logic_;

  public:
    explicit session(tcp::socket&&                     socket,
                     std::shared_ptr<AppDomain::Logic> logic)
        : ws_(std::move(socket))
        , logic_(logic) {}

现在,我们需要向侦听器注入逻辑,以便我们可以传递它:

class listener : public std::enable_shared_from_this<listener> {
    net::any_io_executor              ex_;
    tcp::acceptor                     acceptor_;
    std::shared_ptr<AppDomain::Logic> logic_;

  public:
    listener(net::any_io_executor ex, tcp::endpoint endpoint,
             std::shared_ptr<AppDomain::Logic> logic)
        : ex_(ex)
        , acceptor_(ex)
        , logic_(logic) {

这样我们就可以传递它:

void on_accept(beast::error_code ec, tcp::socket socket) {
    if (ec) {
        fail(ec, "accept");
    } else {
        std::make_shared<session>(std::move(socket), logic_)->run();
    }

    // Accept another connection
    do_accept();
}

现在在 main 中编写真正的逻辑:

auto logic = std::make_shared<AppDomain::Logic>("StackOverflow Demo/");

try {
    // The io_context is required for all I/O
    net::thread_pool ioc(threads);

    std::make_shared<listener>(ioc.get_executor(),
                               tcp::endpoint{address, port}, logic)
        ->run();

    ioc.join();
} catch (beast::system_error const& se) {
    fail(se.code(), "listener");
}

演示逻辑

只是为了好玩,让我们实现一些随机逻辑,这些逻辑将来可能会在硬件中实现:

namespace AppDomain {
    struct Logic {
        std::string banner;
        Logic(std::string msg) : banner(std::move(msg)) {}

        std::string Process(std::string request) {
            std::cout << "Processing: " << std::quoted(request) << std::endl;

            std::string result;

            auto fold = [&result](auto op, double initial) {
                return [=, &result](auto& ctx) {
                    auto& args = _attr(ctx);
                    auto  v = accumulate(args.begin(), args.end(), initial, op);
                    result  = "Fold:" + std::to_string(v);
                };
            };

            auto invalid = [&result](auto& ctx) {
                result = "Invalid Command: " + _attr(ctx);
            };

            using namespace boost::spirit::x3;
            auto args = rule<void, std::vector<double>>{} = '(' >> double_ % ',' >> ')';
            auto add = "adding"      >> args[fold(std::plus<>{}, 0)];
            auto mul = "multiplying" >> args[fold(std::multiplies<>{}, 1)];
            auto err = lexeme[+char_][invalid];

            phrase_parse(begin(request), end(request), add | mul | err, blank);

            return banner + result;
        }
    };
} // namespace AppDomain

现在您可以看到它的实际效果:完整列表 https://godbolt.org/z/nPrW3Kj7Y

从这往哪儿走

如果您需要对一个请求进行多个响应怎么办?

你需要一个队列。我通常称这些为outbox so 会举很多例子。

这些示例还将展示如何处理可以“外部启动”写入的其他情况,以及如何安全地将这些情况排入队列。也许这里有一个非常吸引人的例子asio中如何批量发送未发送的消息 https://stackoverflow.com/questions/71141575/how-to-batch-send-unsent-messages-in-asio/71145869#71145869

列表供参考

万一链接将来失效:

#include <boost/algorithm/string/trim.hpp>
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <filesystem>
#include <functional>
#include <iostream>

static std::string g_app_name = "app-logic-service";

#include <boost/core/demangle.hpp>  // just for our demo logic
#include <boost/spirit/home/x3.hpp> // idem
#include <numeric>                  // idem

namespace AppDomain {
    struct Logic {
        std::string banner;
        Logic(std::string msg) : banner(std::move(msg)) {}

        std::string Process(std::string request) {
            std::string result;

            auto fold = [&result](auto op, double initial) {
                return [=, &result](auto& ctx) {
                    auto& args = _attr(ctx);
                    auto  v = accumulate(args.begin(), args.end(), initial, op);
                    result  = "Fold:" + std::to_string(v);
                };
            };

            auto invalid = [&result](auto& ctx) {
                result = "Invalid Command: " + _attr(ctx);
            };

            using namespace boost::spirit::x3;
            auto args = rule<void, std::vector<double>>{} = '(' >> double_ % ',' >> ')';
            auto add = "adding"      >> args[fold(std::plus<>{}, 0)];
            auto mul = "multiplying" >> args[fold(std::multiplies<>{}, 1)];
            auto err = lexeme[+char_][invalid];

            phrase_parse(begin(request), end(request), add | mul | err, blank);

            return banner + result;
        }
    };
} // namespace AppDomain

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 net       = boost::asio;          // from <boost/asio.hpp>
using tcp           = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>

// Report a failure
void fail(beast::error_code ec, char const* what) {
    std::cerr << what << ": " << ec.message() << "\n";
}

class session : public std::enable_shared_from_this<session> {
    websocket::stream<beast::tcp_stream> ws_;
    beast::flat_buffer                   buffer_;
    std::string                          response_;
    std::shared_ptr<AppDomain::Logic>    logic_;

public:
    explicit session(tcp::socket&&                     socket,
                    std::shared_ptr<AppDomain::Logic> logic)
        : ws_(std::move(socket))
        , logic_(logic) {}

    void run() {
        // Get on the correct executor
        // strand for thread safety
        dispatch(
            ws_.get_executor(),
            beast::bind_front_handler(&session::on_run, shared_from_this()));
    }

private:
    void on_run() {
        // Set suggested timeout settings for the websocket
        ws_.set_option(websocket::stream_base::timeout::suggested(
            beast::role_type::server));

        // Set a decorator to change the Server of the handshake
        ws_.set_option(websocket::stream_base::decorator(
            [](websocket::response_type& res) {
                res.set(http::field::server,
                        std::string(BOOST_BEAST_VERSION_STRING) + " " +
                            g_app_name);
            }));

        // Accept the websocket handshake
        ws_.async_accept(
            beast::bind_front_handler(&session::on_accept, shared_from_this()));
    }

    void on_accept(beast::error_code ec) {
        if (ec)
            return fail(ec, "accept");

        do_read();
    }

    void do_read() {
        ws_.async_read(
            buffer_,
            beast::bind_front_handler(&session::on_read, shared_from_this()));
    }

    void on_read(beast::error_code ec, std::size_t /*bytes_transferred*/) {
        if (ec == websocket::error::closed) return;
        if (ec.failed())                    return fail(ec, "read");

        // Process the message
        auto request = boost::algorithm::trim_copy(
            beast::buffers_to_string(buffer_.data()));

        std::cout << "Processing: " << std::quoted(request) << " from "
                << beast::get_lowest_layer(ws_).socket().remote_endpoint()
                << std::endl;

        response_ = logic_->Process(request);

        ws_.async_write(
            net::buffer(response_),
            beast::bind_front_handler(&session::on_write, shared_from_this()));
    }

    void on_write(beast::error_code ec, std::size_t bytes_transferred) {
        boost::ignore_unused(bytes_transferred);

        if (ec)
            return fail(ec, "write");

        // Clear the buffer
        buffer_.consume(buffer_.size());

        // Do another read
        do_read();
    }
};

// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener> {
    net::any_io_executor              ex_;
    tcp::acceptor                     acceptor_;
    std::shared_ptr<AppDomain::Logic> logic_;

public:
    listener(net::any_io_executor ex, tcp::endpoint endpoint,
            std::shared_ptr<AppDomain::Logic> logic)
        : ex_(ex)
        , acceptor_(ex)
        , logic_(logic) {
        acceptor_.open(endpoint.protocol());
        acceptor_.set_option(tcp::acceptor::reuse_address(true));
        acceptor_.bind(endpoint);
        acceptor_.listen(tcp::acceptor::max_listen_connections);
    }

    // Start accepting incoming connections
    void run() { do_accept(); }

private:
    void do_accept() {
        // The new connection gets its own strand
        acceptor_.async_accept(make_strand(ex_),
                            beast::bind_front_handler(&listener::on_accept,
                                                        shared_from_this()));
    }

    void on_accept(beast::error_code ec, tcp::socket socket) {
        if (ec) {
            fail(ec, "accept");
        } else {
            std::make_shared<session>(std::move(socket), logic_)->run();
        }

        // Accept another connection
        do_accept();
    }
};

int main(int argc, char* argv[]) {
    g_app_name = std::filesystem::path(argv[0]).filename();

    if (argc != 4) {
        std::cerr << "Usage: " << g_app_name << " <address> <port> <threads>\n"
                << "Example:\n"
                << "    " << g_app_name << " 0.0.0.0 8080 1\n";
        return 1;
    }
    auto const address = net::ip::make_address(argv[1]);
    auto const port    = static_cast<uint16_t>(std::atoi(argv[2]));
    auto const threads = std::max<int>(1, std::atoi(argv[3]));

    auto logic = std::make_shared<AppDomain::Logic>("StackOverflow Demo/");

    try {
        // The io_context is required for all I/O
        net::thread_pool ioc(threads);

        std::make_shared<listener>(ioc.get_executor(),
                                tcp::endpoint{address, port}, logic)
            ->run();

        ioc.join();
    } catch (beast::system_error const& se) {
        fail(se.code(), "listener");
    }
}

UPDATE

为了回应这些评论,我再次具体化了发件箱模式。注意代码中的一些注释。

编译器资源管理器 https://godbolt.org/z/bv4EPTWd6

#include <boost/algorithm/string/trim.hpp>
#include <boost/asio.hpp>
#include <boost/beast.hpp>
#include <deque>
#include <filesystem>
#include <functional>
#include <iostream>
#include <list>

static std::string g_app_name = "app-logic-service";

#include <boost/core/demangle.hpp>  // just for our demo logic
#include <boost/spirit/home/x3.hpp> // idem
#include <numeric>                  // idem

namespace AppDomain {
    struct Logic {
        std::string banner;
        Logic(std::string msg) : banner(std::move(msg)) {}

        std::string Process(std::string request) {
            std::string result;

            auto fold = [&result](auto op, double initial) {
                return [=, &result](auto& ctx) {
                    auto& args = _attr(ctx);
                    auto  v = accumulate(args.begin(), args.end(), initial, op);
                    result  = "Fold:" + std::to_string(v);
                };
            };

            auto invalid = [&result](auto& ctx) {
                result = "Invalid Command: " + _attr(ctx);
            };

            using namespace boost::spirit::x3;
            auto args = rule<void, std::vector<double>>{} = '(' >> double_ % ',' >> ')';
            auto add = "adding"      >> args[fold(std::plus<>{}, 0)];
            auto mul = "multiplying" >> args[fold(std::multiplies<>{}, 1)];
            auto err = lexeme[+char_][invalid];

            phrase_parse(begin(request), end(request), add | mul | err, blank);

            return banner + result;
        }
    };
} // namespace AppDomain

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 net       = boost::asio;          // from <boost/asio.hpp>
using tcp           = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp>

// Report a failure
void fail(beast::error_code ec, char const* what) {
    std::cerr << what << ": " << ec.message() << "\n";
}

class session : public std::enable_shared_from_this<session> {
    websocket::stream<beast::tcp_stream> ws_;
    beast::flat_buffer                   buffer_;
    std::shared_ptr<AppDomain::Logic>    logic_;

public:
    explicit session(tcp::socket&&                     socket,
                    std::shared_ptr<AppDomain::Logic> logic)
        : ws_(std::move(socket))
        , logic_(logic) {}

    void run() {
        // Get on the correct executor
        // strand for thread safety
        dispatch(
            ws_.get_executor(),
            beast::bind_front_handler(&session::on_run, shared_from_this()));
    }

    void post_message(std::string msg) {
        post(ws_.get_executor(),
            [self = shared_from_this(), this, msg = std::move(msg)] {
                do_post_message(std::move(msg));
            });
    }

private:
    void on_run() {
        // on the strand
        // Set suggested timeout settings for the websocket
        ws_.set_option(websocket::stream_base::timeout::suggested(
            beast::role_type::server));

        // Set a decorator to change the Server of the handshake
        ws_.set_option(websocket::stream_base::decorator(
            [](websocket::response_type& res) {
                res.set(http::field::server,
                        std::string(BOOST_BEAST_VERSION_STRING) + " " +
                            g_app_name);
            }));

        // Accept the websocket handshake
        ws_.async_accept(
            beast::bind_front_handler(&session::on_accept, shared_from_this()));
    }

    void on_accept(beast::error_code ec) {
        // on the strand
        if (ec)
            return fail(ec, "accept");

        do_read();
    }

    void do_read() {
        // on the strand
        buffer_.clear();

        ws_.async_read(
            buffer_,
            beast::bind_front_handler(&session::on_read, shared_from_this()));
    }

    void on_read(beast::error_code ec, std::size_t /*bytes_transferred*/) {
        // on the strand
        if (ec == websocket::error::closed) return;
        if (ec.failed())                    return fail(ec, "read");

        // Process the message
        auto request = boost::algorithm::trim_copy(
            beast::buffers_to_string(buffer_.data()));

        std::cout << "Processing: " << std::quoted(request) << " from "
                << beast::get_lowest_layer(ws_).socket().remote_endpoint()
                << std::endl;

        do_post_message(logic_->Process(request)); // already on the strand

        do_read();
    }

    std::deque<std::string> _outbox;

    void do_post_message(std::string msg) {
        // on the strand
        _outbox.push_back(std::move(msg));

        if (_outbox.size() == 1)
            do_write_loop();
    }

    void do_write_loop() {
        // on the strand
        if (_outbox.empty())
            return;

        ws_.async_write( //
            net::buffer(_outbox.front()),
            [self = shared_from_this(), this] //
            (beast::error_code ec, size_t bytes_transferred) {
                // on the strand
                boost::ignore_unused(bytes_transferred);

                if (ec)
                    return fail(ec, "write");

                _outbox.pop_front();
                do_write_loop();
            });
    }
};

// Accepts incoming connections and launches the sessions
class listener : public std::enable_shared_from_this<listener> {
    net::any_io_executor              ex_;
    tcp::acceptor                     acceptor_;
    std::shared_ptr<AppDomain::Logic> logic_;

public:
    listener(net::any_io_executor ex, tcp::endpoint endpoint,
            std::shared_ptr<AppDomain::Logic> logic)
        : ex_(ex)
        , acceptor_(make_strand(ex)) // NOTE to guard sessions_
        , logic_(logic) {
        acceptor_.open(endpoint.protocol());
        acceptor_.set_option(tcp::acceptor::reuse_address(true));
        acceptor_.bind(endpoint);
        acceptor_.listen(tcp::acceptor::max_listen_connections);
    }

    // Start accepting incoming connections
    void run() { do_accept(); }

    void broadcast(std::string msg) {
        post(acceptor_.get_executor(),
            beast::bind_front_handler(&listener::do_broadcast,
                                    shared_from_this(), std::move(msg)));
    }

private:
    using handle_t = std::weak_ptr<session>;
    std::list<handle_t> sessions_;

    void do_broadcast(std::string const& msg) {
        for (auto handle : sessions_)
            if (auto sess = handle.lock())
                sess->post_message(msg);
    }

    void do_accept() {
        // The new connection gets its own strand
        acceptor_.async_accept(make_strand(ex_),
                            beast::bind_front_handler(&listener::on_accept,
                                                        shared_from_this()));
    }

    void on_accept(beast::error_code ec, tcp::socket socket) {
        // on the strand
        if (ec) {
            fail(ec, "accept");
        } else {
            auto sess = std::make_shared<session>(std::move(socket), logic_);
            sessions_.emplace_back(sess);
            // optionally:
            sessions_.remove_if(std::mem_fn(&handle_t::expired));
            sess->run();
        }

        // Accept another connection
        do_accept();
    }
};

static void emulate_hardware_stuff(std::shared_ptr<listener> srv) {
    using std::this_thread::sleep_for;
    using namespace std::chrono_literals;
    // Extremely simplistic. Instead I'd recommend `steady_timer` with
    // `_async_wait` here, but since I'm just making a sketch...
    unsigned i = 0;

    while (true) {
        sleep_for(1s);
        srv->broadcast("Hardware thing #" + std::to_string(++i));
    }
}

int main(int argc, char* argv[]) {
    g_app_name = std::filesystem::path(argv[0]).filename();

    if (argc != 4) {
        std::cerr << "Usage: " << g_app_name << " <address> <port> <threads>\n"
                << "Example:\n"
                << "    " << g_app_name << " 0.0.0.0 8080 1\n";
        return 1;
    }
    auto const address = net::ip::make_address(argv[1]);
    auto const port    = static_cast<uint16_t>(std::atoi(argv[2]));
    auto const threads = std::max<int>(1, std::atoi(argv[3]));

    auto logic = std::make_shared<AppDomain::Logic>("StackOverflow Demo/");

    try {
        // The io_context is required for all I/O
        net::thread_pool ioc(threads);

        auto srv = std::make_shared<listener>( //
            ioc.get_executor(),                     //
            tcp::endpoint{address, port},           //
            logic);

        srv->run();

        std::thread something_hardware(emulate_hardware_stuff, srv);

        ioc.join();
        something_hardware.join();
    } catch (beast::system_error const& se) {
        fail(se.code(), "listener");
    }
}

通过现场演示:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Boost Beast 异步 Websocket 服务器 如何与会话交互? 的相关文章

  • 通过 SocketCAN 进行 boost::asio

    我正在考虑利用升压阿西奥 http www boost org doc libs 1 49 0 doc html boost asio html从a读取数据套接字CAN http en wikipedia org wiki SocketCA
  • 在 C/C++ 中获得正模数的最快方法

    通常在我的内部循环中 我需要以 环绕 方式索引数组 因此 例如 如果数组大小为 100 并且我的代码要求元素 2 则应该给它元素 98 高级语言 例如 Python 可以简单地使用my array index array size 但由于某
  • 在 C# 中按元素相乘数组具有意想不到的性能

    我想找到按元素相乘两个数组的最佳方法 这是更广泛项目的一部分 其中性能而不是唯一的考虑因素 我今天开始用 C Linqpad 编写一些函数 因此它还没有以任何方式进行优化 下面代码的输出如下 Environment ProcessorCou
  • 我如何在 C# .NET(win7 手机)中使用“DataContractJsonSerializer”读入“嵌套”Json 文件?

    我有一个问题 如果我的 json 文件看起来像这样 Numbers 45387 Words 空间桶 我可以很好地阅读它 但是如果它看起来像这样 Main Numbers 45387 Words 空间桶 某事 数字 12345 单词 克兰斯基
  • 如何在 C# 控制台应用程序中将修饰符(ctrl、alt、shift)按键捕获为单个按键?

    Console ReadKey 仅在按下 正常 键时捕获输入 然后将修饰符 如果有 附加为键信息的一部分 如何将单个修饰键注册为输入 提供了一种解决方案这个链接 https blogs msdn microsoft com toub 200
  • fprintf() 线程安全吗?

    我正在为野人就餐问题的某些变量编写一个 C 解决方案 现在 我创建线程 每个线程都将 FILE 获取到同一个调试文件 在线程内我正在使用 fprintf 进行一些打印 打印的语句不受任何类型的互斥锁等保护 我没有在调试文件中观察到任何交错行
  • 类的成员复制

    在学习 复制成员 概念时 书中给出了如下说法 此外 如果非静态成员是引用 const 或没有复制赋值的用户定义类型 则无法生成默认赋值 我不太明白这个声明到底想传达什么 或者说这个说法指的是哪一种场景 谢谢 该语句与编译器自动为您编写的类
  • vs2008 c#:Facebook.rest.api如何使用它来获取好友列表?

    如何在此基础上取得进一步的进步 获取好友列表的下一步是什么 string APIKey ConfigurationManager AppSettings API Key string APISecret ConfigurationManag
  • Visual Studio Code:如何配置 includePath 以获得更好的 IntelliSense 结果

    我是使用 Visual Studio Code 的完全初学者 我不知道我在做什么 我已经四处搜索 也许还不够 但我找不到像我这样的人如何配置的简单解释c cpp properties json每当我单击带有绿色波浪线下划线的行旁边的黄色灯泡
  • C++ php 和静态库

    我创建了一个library a 其中包含 cpp 和 h 文件 其中包含很多类 嵌套类和方法 我想在 php 示例中包含这个静态库并尝试使用它 我想提一下 我是 php 新手 我已经在 test cpp 文件中测试了我的 libray a
  • AES 输出是否小于输入?

    我想加密一个字符串并将其嵌入到 URL 中 因此我想确保加密的输出不大于输入 AES 是可行的方法吗 不可能创建任何始终会创建比输入更小的输出的算法 但可以将任何输出反转回输入 如果您允许 不大于输入 那么基本上您只是在谈论同构算法alwa
  • 无法在内存位置找到异常源:cudaError_enum

    我正在尝试确定 Microsoft C 异常的来源 test fft exe 中 0x770ab9bc 处的第一次机会异常 Microsoft C 异常 内存位置 0x016cf234 处的 cudaError enum 我的构建环境是 I
  • 如何通过 JsonConvert.DeserializeObject 在动态 JSON 中使用 null 条件运算符

    我正在使用 Newtonsoft 反序列化已知的 JSON 对象并从中检索一些值 如果存在 关键在于对象结构可能会不断变化 因此我使用动态来遍历结构并检索值 由于对象结构不断变化 我使用 null 条件运算符来遍历 JSON 代码看起来像这
  • 每个租户的唯一用户名和电子邮件

    我正在使用以下代码编写多租户应用程序ASP NET Core 2 1 我想覆盖默认的与用户创建相关的验证机制 目前我无法创建多个具有相同的用户UserName My ApplicationUser模型有一个名为TenantID 我想要实现的
  • 在 EnvDTE 中调试时捕获 VS 局部变量

    是否可以使用 EnvDTE 进行 vsix Visual Studio 扩展来捕获本地和调试窗口使用的调试数据 或者可以通过其他方法吗 我想创建一个自定义的本地窗口 我们可以修改它以根据需要显示一些较重的内容 而无需为高级用户牺牲原始的本地
  • .NET Core 中的跨平台文件名处理

    如何处理文件名System IO以跨平台方式运行类以使其在 Windows 和 Linux 上运行 例如 我编写的代码在 Windows 上完美运行 但它不会在 Ubuntu Linux 上创建文件 var tempFilename Dat
  • 我可以让 ungetc 取消阻止阻塞的 fgetc 调用吗?

    我想在收到 SIGUSR1 后使用 ungetc 将 A 字符重新填充到标准输入中 想象一下我有充分的理由这样做 调用 foo 时 stdin 中的阻塞读取不会被收到信号时的 ungetc 调用中断 虽然我没想到它会按原样工作 但我想知道是
  • IEnumerable.Except 不起作用,那么我该怎么办?

    我有一个 linq to sql 数据库 非常简单 我们有 3 个表 项目和用户 有一个名为 User Projects 的连接表将它们连接在一起 我已经有了一个获得的工作方法IEnumberable
  • 您是否将信息添加到每个 .hpp/.cpp 文件的顶部? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 创建新的 C 头文件 源文件时 您会在顶部添加哪些信息 例如 您是否添加日期 您的姓名 文件描述等 您是否使用结构化格式来存储此信息 e g F
  • xsi:type 属性搞乱了 C# XML 反序列化

    我使用 XSD exe 根据 XML 架构 xsd 文件 自动生成 C 对象 我正在反序列化 OpenCover 输出 但其中一个部分类未正确生成 这是导致异常的行

随机推荐

  • C# 访问字段语法

    如果我只有要访问的变量的名称 我将如何访问对象的变量值 在 C 中 假设我有一个变量名称列表 表示为数组中的字符串 例如 我如何循环访问它们 我可以在 Actionscript 中执行类似以下操作 var arrayOfVariableNa
  • 如何从我的 makefile 中调用特定目标?

    a echo 1 b echo 2 c if d somefolder then how do I invoke target b here fi 我如何调用目标b内部目标c 根据我的情况 有点像antcall 如果你熟悉 ant 的话 说
  • 如何在 MiUi pre - Marshmallow 中请求权限?

    int permissionCheck ContextCompat checkSelfPermission mActivity Manifest permission RECEIVE SMS ActivityCompat requestPe
  • 如何确定应用程序中使用了哪些 JAR

    现有应用程序的类路径中有大量 JAR 文件 为了确定起见 最初必须有人添加所有 JAR 有些 JAR 显然没有被使用 我们已经删除了其中一些不需要的 JAR 没有造成任何问题 如何确定哪些 JAR 正在使用 哪些 JAR 不需要 除了试错法
  • Django 性能测试套件将报告指标(数据库查询等)

    我有一个复杂的 Django Web 应用程序 其中投入了很多人年的工作 有时可能需要优化 我可以使用 例如 django 的测试客户端编写几个常见的操作 流程的脚本 是否有一些程序 给定这样的 python 脚本 然后将运行 并报告各种
  • C++ 投掷类成员

    我有以下 C 代码 template
  • 查找数组中的重复元素?

    我看到一个面试题是这样的 数组中有一个数字重复 找到它 简单的解决方案如下 for int i 0 i
  • REST API 的试运行策略

    我正在寻找 REST API 的 试运行 操作的一些最佳实践 假设我有一个端点将资金从账户 A 转账到账户 B 我可以像这样发起转账 POST transactions amount 1000 how much to transfer so
  • jQuery 数据绑定 - 现在流行的插件是什么?

    我需要某种类型的 JS MVC DataBinding 解决方案 与实施 GMAIL Web 应用程序类似 消息索引和消息显示 在消息显示的位置 如果您修改消息 它会自动在消息索引中更新 我应该学习什么插件才能在不使用大量 jQuery 的
  • Tensorflow 中的入队和增量变量

    如何使张量流图将递 增的数字推送到队列 我这样做只是为了学习目的 所以我希望您保持它与我正在做的事情相似 并纠正我做错的事情 这是我的代码 import tensorflow as tf create queue queue tf Rand
  • 通过 attr_accessor 对模型对象进行排序

    当我必须对对象列表进行排序时 我认为 attr accessor 具有与另一个相同的行为 但似乎有所不同 dataRecords MyData where day Time now yesterday strftime Y m d to i
  • 仅禁用自动生成的表单上的特定“绿色加号”图标

    如何在自动生成的表单中禁用特定 manytomany 或 foreignkey 字段上的绿色图标 使用CSS如下 add another display none 禁用所有我不想要的 一个例子是工作日模型 存储从星期一到星期日的天数 指向该
  • Python 的多处理和内存

    我在用multiprocessing imap unordered对值列表执行计算 def process parallel fnc some list pool multiprocessing Pool for result in poo
  • 来自 Cordova iOS 插件的后续回调不会触发

    我在从 cordova 插件 iOS 插件 立即触发后续回调时遇到麻烦 在 XCode 调试器中 我清楚地看到它跳过了 self commandDelegate sendPluginResult pluginResult callbackI
  • ORA-01036: 通过 C# 运行查询时非法变量名称/编号

    我正在尝试使用ALTER USER在以下代码中 使用 C 中的 OracleCommand 查询 Oracle 数据库 如果用户名和密码的值不是空字符串 它将创建查询 但我收到一个错误 ORA 01036 illegal variable
  • 与带有分隔符的 String.Split 相反 (.net)

    有没有办法做相反的事情String Split在 Net 中 也就是说 用给定的分隔符组合数组的所有元素 Taking a b c 和给予 a b c 带有分隔符 UPDATE 我自己找到了答案 它是String Join method 找
  • 从 MS Excel 访问 Redis?

    我想使用 Redis 从命令行 脚本 Web 和电子表格中查询数据 除了电子表格之外 我可以找到很好的例子 不过 我不太知道从哪里开始访问 MS Excel 电子表格 谷歌让我失望了 请让我知道您建议如何执行此操作 谢谢 附注对于那些不熟悉
  • Spring MVC 请求映射

    我正处于学习使用 Spring MVC 的早期阶段 我创建了一个控制器并应用了RequestMapping对其进行注释 当我运行该项目时 索引页面按预期显示index htm 但是当我导航到应该指向我的控制器的 URI 时 我收到 404
  • 使用 HttpModule 进行本地化安全吗?

    我正在考虑使用 HttpModule 进行本地化 基于中的示例 本文 http weblogs manas com ar smedina 2008 12 17 internationalization in aspnet mvc 但我很好奇
  • Boost Beast 异步 Websocket 服务器 如何与会话交互?

    所以我不知道为什么 但我无法理解 boost Beast websocket 服务器以及如何 或应该 与其交互 我制作的基本程序看起来像这样 跨 2 个类 WebSocketListener and WebSocketSession htt