我正在开发一个 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 没有停止,所以我不确定会发生什么。