Reputation: 351
I want to create a server that can receive data async using boost::asio
from software like PacketSender, but when i try as below it crashes.
This is how my code looks like:
IoServiceWork.h - which is a singleton class as per this link
#include <boost/asio.hpp>
#include <boost/thread/thread.hpp>
class IoServiceWork
{
public:
IoServiceWork()
: m_ioService(new boost::asio::io_service()),
m_ioServiceWork(new boost::asio::io_service::work(*m_ioService)),
m_ioWorkThread(new boost::thread(boost::bind(&boost::asio::io_service::run, m_ioService)))
{
}
~IoServiceWork()
{
delete m_ioServiceWork;
m_ioWorkThread->join();
delete m_ioWorkThread;
delete m_ioService;
}
boost::asio::io_service& ioService()
{
return *m_ioService;
}
boost::asio::io_service* m_ioService;
boost::asio::io_service::work* m_ioServiceWork;
boost::thread* m_ioWorkThread;
};
CustomIOService.h - This class creates a seperate thread for io_service to not hold my rest of codes execution.
#include <boost/asio.hpp>
boost::asio::io_service& IOService();
CustomIOService.cpp
#include "CustomIOService.h"
#include "IoServiceWork.h"
boost::asio::io_service& IOService()
{
static IoServiceWork ioServiceWork;
return ioServiceWork.ioService();
}
Here's how i call this in my DLL
server ser(IOService(), 7777);
when the execution of the program in my DLL reaches this point it'll throw Mutex lock error, i couldn't able to debug but when application crashes i can attach.
i have tried to create a sperate work thread for io_service(), but not succeeded.
boost::asio::io_service io_service;
auto_ptr<boost::asio::io_service::work> work(new boost::asio::io_service::work(io_service));
server ser(work->io_service(), 7777);
Here's my server class looks like
server.h class server { public: server(boost::asio::io_service& io_service, short port);
private:
void start_accept();
void handle_accept(session* new_session, const boost::system::error_code& error);
boost::asio::io_service& io_service_;
tcp::acceptor acceptor_;
};
server.cpp
server::server(boost::asio::io_service& io_service, short port) : io_service_(io_service), acceptor_(io_service, tcp::endpoint(tcp::v4(), port))
{
start_accept();
}
void server::start_accept()
{
session* new_session = new session(io_service_);
acceptor_.async_accept(new_session->socket(), boost::bind(&server::handle_accept, this, new_session, boost::asio::placeholders::error));
}
void server::handle_accept(session* new_session, const boost::system::error_code& error)
{
if (!error)
{
new_session->start();
}
else
{
delete new_session;
}
start_accept();
}
Where i am doing wrong, is there any way to make it run.
Edit: Any Suggestion please...
Upvotes: 0
Views: 925
Reputation: 2814
Boost ASIO in boost/asio/detail/winsock_init.hpp
will try to initialize winsock using a static member variable. This doesn't play well with DLLs because you are not allowed to make calls to any DLL other than Kernel32.dll from DllMain or global and static C++ object constructors. In fact even some Kernel32 functions are out of limits as they themselves load other Dlls.
The breaking of this rule can cause Access violation exceptions on load or on termination.
Read more things that you are not allowed to do in DllMain and static/globals in DllMain entry point article
Luckily there is a comment in winsock_init.hpp which reads as follows:
This class may be used to indicate that user code will manage Winsock initialisation and cleanup. This may be required in the case of a DLL, for example, where it is not safe to initialise Winsock from global object constructors.
To prevent asio from initialising Winsock, the object must be constructed before any Asio's own global objects. With MSVC, this may be accomplished by adding the following code to the DLL:
#pragma warning(push)
#pragma warning(disable:4073)
#pragma init_seg(lib)
boost::asio::detail::winsock_init<>::manual manual_winsock_init;
#pragma warning(pop)
So add this code to a cpp file of your dll, to prevent calling the WS32_api.dll methods. An error you may get for example is while your application is exiting, it unloads WS32_api.dll before your dll, so calling WSACleanup from the static global will crash it.
Upvotes: 0
Reputation: 351
I have googled so much to resolve my above stated problem but nobody replied so i tried so many trial and error conditions and one of them working perfectly.
Here's what i did
i have created a static function as below
static void startServer()
{
boost::asio::io_service ioservice;
server ser(ioservice, 7777);
ioservice.run()
}
wherever i have to start the server just call as below and your server will start.
boost::Thread t(&startServer);//Make sure that no brackets while calling.
Now this can be used in DLL or in Static Library or in exe, your server runs in seperate thread, eventhough if it throws an exception it'll not affect to the application in which it was called so it is thread safe as well.
Well This solution may help somebody.
Regards,
Jithendrakumar K.
Upvotes: 1