1

我正在开发一个 NPAPI 插件,它允许在浏览器内部使用本地套接字,我正在为此使用 Boost 套接字。

我现在的用法只是打开套接字写入消息,读取,发送关闭消息并关闭然后重复(我知道每次关闭和打开都很愚蠢,但我无法更改)。

问题是在第二次打开后我无法从套接字读取,直到 las 更改我能够打开写入但从未得到信息,现在看来 io_service 线程正在死去。

我已经阅读了很多教程和信息,但似乎没有人像我试图做的那样打开多个客户端套接字。

这是存储套接字信息和处理程序的类:

套接字信息.hpp

class SocketInfo
{
public:
    void start_read();
    void handle_read(const boost::system::error_code& error, std::size_t bytes_transferred);

    FB::JSObjectPtr m_callback;
    boost::shared_ptr<boost::asio::ip::tcp::socket> m_socket;
    char data_[SOCKETS_API_BUFFER];
    int key;
    boost::shared_ptr<SocketsAPI> parent;
};

套接字信息.cpp

void SocketInfo::start_read()
{
    parent->log("start_read" + boost::lexical_cast<std::string>(key));
    m_socket->async_receive(boost::asio::buffer(data_, SOCKETS_API_BUFFER),
        boost::bind(&SocketInfo::handle_read, this, 
            boost::asio::placeholders::error,
            boost::asio::placeholders::bytes_transferred));
}

void SocketInfo::handle_read(const boost::system::error_code& error,
        std::size_t bytes_transferred)
{
    if (!error) {
        parent->log("handle_read" + boost::lexical_cast<std::string>(key));
        std::string str(&data_[0], &data_[0] + bytes_transferred);
        m_callback->InvokeAsync("processData", FB::variant_list_of(str));
        start_read();
    } else {
        parent->log("error closing " + boost::lexical_cast<std::string>(key));
        m_callback->InvokeAsync("processCancel", FB::variant_list_of());
        parent->do_close(*this);
    }
}

套接字API.h

class SocketsAPI : public FB::JSAPIAuto
{
public:
    SocketsAPI(const SocketsPtr& plugin, const FB::BrowserHostPtr& host) :
        m_plugin(plugin), m_host(host)          
    {
... FireBreath code here ...

        //Start thread with work
        workPtr.reset( new boost::asio::io_service::work(io_service));
        ioThreadPtr.reset(new boost::thread(boost::bind(&boost::asio::io_service::run, &io_service)));

    }

    virtual ~SocketsAPI() {
        workPtr.reset();
        if (ioThreadPtr) {
            ioThreadPtr->join();
        }
    };

    //Socket Methods
    int open(const int port, const FB::JSObjectPtr &callback );
    void close(const int key);
    void write(const int key, const std::string data);

    // Method echo
    FB::variant echo(const FB::variant& msg);
    void do_close(const SocketInfo socket);
    void log(const std::string &str);

private:

    mapType sockets;

    boost::asio::io_service io_service;
    boost::shared_ptr<boost::thread> ioThreadPtr;
    boost::shared_ptr<boost::asio::io_service::work> workPtr;

    void checkOpen(const SocketInfo socket);
    void do_write(const std::string data, const SocketInfo socket);
    void start_read(const SocketInfo socket);
    void empty_handle(const boost::system::error_code& error);
    int getFirstEmpty();
    SocketInfo getSocket(const int key);
};

套接字API.cpp

int SocketsAPI::open(const int port, const FB::JSObjectPtr &callback )
{
    log("open");
    boost::shared_ptr<SocketInfo> socket;
    socket.reset(new SocketInfo);
    socket->m_socket.reset(new boost::asio::ip::tcp::socket(io_service));
    socket->m_callback = callback;
    ip::tcp::endpoint tcp(ip::address::from_string("127.0.0.1"), port);

    boost::system::error_code errorcode;
    socket->m_socket->connect(tcp, errorcode);
    if (errorcode) {
        trace("Connection failed: ", errorcode.message());
        return -1;
    }
    log("conenected");
    boost::asio::socket_base::keep_alive o(true);
    socket->m_socket->set_option(o);
    int key = getFirstEmpty();
    socket->key = key;
    socket->parent.reset(this);
    sockets.insert ( std::pair<int,boost::shared_ptr<SocketInfo>>(key,socket));
    socket->start_read();
    if (io_service.stopped()) {
        log("Resetting service");
        io_service.reset();
    }
    return key;
}

void SocketsAPI::close(const int key)
{
    SocketInfo socket = getSocket(key);
    checkOpen(socket);
    log("close");
    io_service.post(boost::bind(&SocketsAPI::do_close, this, socket));
}

void SocketsAPI::write(const int key, const std::string data)
{
    log("write socket " + boost::lexical_cast<std::string>(key));
    SocketInfo socket = getSocket(key);
    checkOpen(socket);
    io_service.post(boost::bind(&SocketsAPI::do_write, this, Base64::decode(data), socket));
}

void SocketsAPI::checkOpen(const SocketInfo socket)
{
    log("checkOpen");
    if (!socket.m_socket || !socket.m_socket->is_open()) {
        trace("Socket not opened", "");
        throw FB::script_error("There is no open socket");
    }
}


void SocketsAPI::do_write(const std::string data,
                            const SocketInfo socket)
{
    log("do_write " + boost::lexical_cast<std::string>(socket.key));
    if (!socket.m_socket->is_open()) {
        return;
    }
    boost::asio::async_write(*(socket.m_socket.get()),
        boost::asio::buffer(&data[0], data.size()),
        boost::bind(&SocketsAPI::empty_handle, this, boost::asio::placeholders::error)
    );
}

void SocketsAPI::empty_handle(const boost::system::error_code& error)
{
    if (error) {
        trace("Error writing: ", error.message());
    }
}

void SocketsAPI::do_close(const SocketInfo socket)
{
    log("do_close");
    if (!socket.m_socket || !socket.m_socket->is_open()) {
        return;
    }   
    boost::system::error_code errorcode;
    socket.m_socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both, errorcode);
    if (errorcode) {
        trace("Closing failed: ", errorcode.message());
    }
    socket.m_socket->close(errorcode);
    if (errorcode) {
        trace("Closing2 failed: ", errorcode.message());
    }
    mapType::iterator iter = sockets.find(socket.key);
    if (iter != sockets.end()) {
        sockets.erase (iter);
    }
    log("do_close end");
}

int SocketsAPI::getFirstEmpty() {
    int i = 0;
    mapType::iterator iter;
    while(true) {
        iter = sockets.find(i);
        if (iter == sockets.end()) {
            return i;
        }
        i++;
    }
}

SocketInfo SocketsAPI::getSocket(const int key) {
    mapType::iterator iter = sockets.find(key);
    if (iter == sockets.end()) {
        trace("Socket not found", "");
        throw FB::script_error("Socket not found");
    }
    log("socket " + boost::lexical_cast<std::string>(key) +" found");
    return *iter->second.get();
}

我确信可以改进某些东西(请告诉我),但我找不到错误,为什么在第二次打开后它就不起作用了。

行刑痕迹:

open 
conenected 
start_read0 
write socket 0 
socket 0 found 
checkOpen 
do_write 0 
handle_read0 
start_read0 
write socket 0 
socket 0 found 
checkOpen 
do_write 0 
socket 0 found 
checkOpen 
close 
do_close 
do_close end 
open 
conenected 
start_read0 
write socket 0 
socket 0 found 
checkOpen 

似乎 io_service.run() 刚刚停止,但线程仍在工作并且 io_service 没有停止,所以我不确定会发生什么。

4

1 回答 1

0

好的,我发现错误比我想象的要简单得多,它只是抛出一个异常并停止一切,但是当我在浏览器中使用它时,我没有注意到这一点。

我仍然无法解决问题,因此您可以检查:Boost bind object freed on read handler以分享一些见解。

于 2013-03-15T18:21:12.200 回答