I've been struggling with this for half a day and it hasn't improved, so here it's:
I have a class called Network Handler that will handle all network connections in a game I'm making in SDL, I'm using SDL_Net for all the networking. Here is my header class:
#ifndef NETWORK_HANDLER
#define NETWORK_HANDLER
#include <iostream>
#include <string>
#include <SDL_net.h>
using namespace std;
class NetworkHandler
{
public:
NetworkHandler();
~NetworkHandler(){}
bool Initialize(bool pIsServer);
void CheckForMessages();
void exit();
private:
UDPpacket* m_packet;
UDPsocket m_socket;
};
#endif
And here is my Class code:
#include "NetworkHandler.h"
NetworkHandler::NetworkHandler():m_packet(new UDPpacket()),m_socket(0)
{
}
bool NetworkHandler::Initialize(bool pIsServer)
{
//Initialize SDL_net
if(SDLNet_Init() < 0)
{
std::cerr<< "SDL Net Error:"<< SDLNet_GetError() << std::endl;
return false;
}
atexit(SDLNet_Quit);
std::cout<< "SDL Net Error:"<< SDLNet_GetError() << std::endl;
m_socket = SDLNet_UDP_Open(2000);
if(!m_socket)
{
std::cerr<< "Socket Error:" <<SDLNet_GetError()<<std::endl;
return false;
}
if(!(m_packet = SDLNet_AllocPacket(512)))
{
std::cerr<<"Packet Error:"<<SDLNet_GetError()<<std::endl;
}
if(!pIsServer)
{
IPaddress ip_server;
if(SDLNet_ResolveHost(&ip_server,"10.167.193.140",2000)<0)
{
std::cerr<<"Failed to connect to Server: " << SDLNet_GetError() <<endl;
return false;
}
}
return true;
}
void NetworkHandler::CheckForMessages()
{
if(SDLNet_UDP_Recv(m_socket,m_packet))
{
std::cout<<m_packet->data<<std::endl;
}
}
void NetworkHandler::exit()
{
SDLNet_FreePacket(m_packet);
SDLNet_Quit();
}
I'm getting the following error:
Unhandled exception at 0x00a3e524 in NetworkGameDevelopmenProject.exe: 0xC0000005: Access violation writing location 0xcdcdcdd1.
At this line:
m_socket = SDLNet_UDP_Open(2000);
And when I take a look at m_socket during debug, it has the following error attached to it:
m_socket CXX0076: Error:
I've already tried cleaning and rebuilding. Funnily enough if I declare m_socket and m_packet locally(inside the function) it doesn't give me any errors. Can anyone think why this is happening?
Related
I created a TCPServer using the Poco::Net::TCPServer framework, that uses a unix domain socket and it seems to work. However if I close the server and start it again I get this error:
Net Exception: Address already in use: /tmp/app.SocketTest
What is the right way to deal with this error?
Are the TCPServerConnections, TCPServerConnectionFactory and sockets
automatically cleaned-up or do I need to implement their destructors or destroy them manually?
EDIT
I have two questions here. The first is answered by using remove() on the socket-file. The other question is, if the clean-up in the Poco::Net::TCPServer framework is automatic or if it has to be manually implemented to prevent memory-leak?
Here is the code for the TCPServer:
#include "Poco/Util/ServerApplication.h"
#include "Poco/Net/TCPServer.h"
#include "Poco/Net/TCPServerConnection.h"
#include "Poco/Net/TCPServerConnectionFactory.h"
#include "Poco/Util/Option.h"
#include "Poco/Util/OptionSet.h"
#include "Poco/Util/HelpFormatter.h"
#include "Poco/Net/StreamSocket.h"
#include "Poco/Net/ServerSocket.h"
#include "Poco/Net/SocketAddress.h"
#include "Poco/File.h"
#include <fstream>
#include <iostream>
using Poco::Net::ServerSocket;
using Poco::Net::StreamSocket;
using Poco::Net::TCPServer;
using Poco::Net::TCPServerConnection;
using Poco::Net::TCPServerConnectionFactory;
using Poco::Net::SocketAddress;
using Poco::Util::ServerApplication;
using Poco::Util::Option;
using Poco::Util::OptionSet;
using Poco::Util::HelpFormatter;
class UnixSocketServerConnection: public TCPServerConnection
/// This class handles all client connections.
{
public:
UnixSocketServerConnection(const StreamSocket& s):
TCPServerConnection(s)
{
}
void run()
{
try
{
/*char buffer[1024];
int n = 1;
while (n > 0)
{
n = socket().receiveBytes(buffer, sizeof(buffer));
EchoBack(buffer);
}*/
std::string message;
char buffer[1024];
int n = 1;
while (n > 0)
{
n = socket().receiveBytes(buffer, sizeof(buffer));
buffer[n] = '\0';
message += buffer;
if(sizeof(buffer) > n && message != "")
{
EchoBack(message);
message = "";
}
}
}
catch (Poco::Exception& exc)
{
std::cerr << "Error: " << exc.displayText() << std::endl;
}
std::cout << "Disconnected." << std::endl;
}
private:
inline void EchoBack(std::string message)
{
std::cout << "Message: " << message << std::endl;
socket().sendBytes(message.data(), message.length());
}
};
class UnixSocketServerConnectionFactory: public TCPServerConnectionFactory
/// A factory
{
public:
UnixSocketServerConnectionFactory()
{
}
TCPServerConnection* createConnection(const StreamSocket& socket)
{
std::cout << "Got new connection." << std::endl;
return new UnixSocketServerConnection(socket);
}
private:
};
class UnixSocketServer: public Poco::Util::ServerApplication
/// The main application class.
{
public:
UnixSocketServer(): _helpRequested(false)
{
}
~UnixSocketServer()
{
}
protected:
void initialize(Application& self)
{
loadConfiguration(); // load default configuration files, if present
ServerApplication::initialize(self);
}
void uninitialize()
{
ServerApplication::uninitialize();
}
void defineOptions(OptionSet& options)
{
ServerApplication::defineOptions(options);
options.addOption(
Option("help", "h", "display help information on command line arguments")
.required(false)
.repeatable(false));
}
void handleOption(const std::string& name, const std::string& value)
{
ServerApplication::handleOption(name, value);
if (name == "help")
_helpRequested = true;
}
void displayHelp()
{
HelpFormatter helpFormatter(options());
helpFormatter.setCommand(commandName());
helpFormatter.setUsage("OPTIONS");
helpFormatter.setHeader("A server application to test unix domain sockets.");
helpFormatter.format(std::cout);
}
int main(const std::vector<std::string>& args)
{
if (_helpRequested)
{
displayHelp();
}
else
{
// set-up unix domain socket
Poco::File socketFile("/tmp/app.SocketTest");
SocketAddress unixSocket(SocketAddress::UNIX_LOCAL, socketFile.path());
// set-up a server socket
ServerSocket svs(unixSocket);
// set-up a TCPServer instance
TCPServer srv(new UnixSocketServerConnectionFactory, svs);
// start the TCPServer
srv.start();
// wait for CTRL-C or kill
waitForTerminationRequest();
// Stop the TCPServer
srv.stop();
}
return Application::EXIT_OK;
}
private:
bool _helpRequested;
};
int main(int argc, char **argv) {
UnixSocketServer app;
return app.run(argc, argv);
}
You don't need to worry about deallocating memory. All is done by library.
TCPServer srv(new UnixSocketServerConnectionFactory, svs);
^^^
Instance of UnixSocketServerConnectionFactory is deleted by TCPServer according to poco ref
The server takes ownership of the TCPServerConnectionFactory and
deletes it when it's no longer needed.
TCPServerConnection* createConnection(const StreamSocket& socket)
{
std::cout << "Got new connection." << std::endl;
return new UnixSocketServerConnection(socket);
^^^
}
instances of UnixSocketServerConnection are deleted by Poco library code as well:
As soon as the run() method returns, the server connection object is
destroyed and the connection is automatically closed.
The problem with Poco::File was that the destructor of Poco::File cannot remove file, you have to do it explicitly by remove method.
I get the following errors:
Severity Code Description Project File Line Suppression State
Error C2143 syntax error: missing ';' before '*' flashlight d:\flashlight\orbslam3\examples\monocular\flashlight.hpp 36
Severity Code Description Project File Line Suppression State
Error C4430 missing type specifier - int assumed. Note: C++ does not
support
default-int flashlight d:\flashlight\orbslam3\examples\monocular\flashlight.hpp 36
Severity Code Description Project File Line Suppression State
Error C2238 unexpected token(s) preceding
';' flashlight d:\flashlight\orbslam3\examples\monocular\flashlight.hpp 36
This is my header flashlight.hpp file:
#ifndef FLASHLIGHT_H
#define FLASHLIGHT_H
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include "orbslam3.hpp"
using boost::asio::ip::udp;
class Flashlight {
public:
Flashlight(boost::asio::io_service& io_service, short port) : io_service_(io_service), socket_(io_service, udp::endpoint(udp::v4(), port)) {
// start receiving udp data
socket_.async_receive_from(
boost::asio::buffer(data_recv_, max_length), sender_endpoint_, boost::bind(&Flashlight::handle_receive_from, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
);
}
void start_loop();
void send_beacon();
void handle_send_to(const boost::system::error_code& error, size_t bytes_sent);
void handle_receive_from(const boost::system::error_code& error, size_t bytes_recvd);
private:
ORBSLAM3 *orbslam; // <= ERRORS APPEAR HERE (Line 36)
boost::asio::io_service& io_service_;
udp::socket socket_;
udp::endpoint sender_endpoint_;
enum { max_length = 1024 };
char data_recv_[max_length];
char data_sent_[max_length];
};
#endif
And this is my implementation file flashlight.cpp:
#include "flashlight.hpp"
using namespace std; // for atoi()
using boost::asio::ip::udp;
int main(int argc, char* argv[]) {
try {
const uint16_t udp_port = 19630;
// thread to run network services asynchronously
boost::thread_group tgroup;
// start udp network endpoint
boost::asio::io_service io_service;
// instantiate flashlight class
Flashlight flashlight(io_service, udp_port);
// run network entities in own thread
tgroup.create_thread(boost::bind(&boost::asio::io_service::run, &io_service));
cout << "Server running on UDP port " << udp_port << endl;
// start main loop
flashlight.start_loop();
// shutdown network threads
tgroup.join_all();
} catch(exception& e) {
cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
void Flashlight::start_loop() {
string sensor_type = "stereo";
string vocab_path = "D:\\Flashlight\\ORBSLAM3\\Examples\\Monocular\\Release\\ORBVoc.bin";
string settings_path = "D:\\Flashlight\\ORBSLAM3\\Examples\\Monocular\\Release\\stereo_2_8_mm_640_480.yaml";
//const string settings_path = "../"+sensor_type+"_"+lens_type+"_mm_"+to_string(cam_width)+"_"+to_string(cam_height)+".yaml";
uint16_t cam_width = 640;
uint16_t cam_height = 480;
// orb slam system initialization
this->orbslam = new ORBSLAM3(sensor_type, vocab_path, settings_path, cam_width, cam_height);
// mainloop
char key;
while((key = std::cin.get()) != 27) {
this->orbslam->loop();
}
// shutdown orbslam threads
this->orbslam->shutdown();
// save camera trajectory
//orbslam->SaveTrajectoryTUM("CameraTrajectory.txt");
}
void Flashlight::send_beacon() {
while(true) {
boost::posix_time::seconds workTime(1);
// send_async(beacon)
std::cout << "Beacon signal sent ..." << std::endl;
boost::this_thread::sleep(workTime);
}
}
void Flashlight::handle_receive_from(const boost::system::error_code& error, size_t bytes_recv) {
if(!error && bytes_recv > 0) {
std::cout << "UDP received: "; for(int i=0; i<bytes_recv; i++) std::cout << (int)data_recv_[i] << ", "; std::cout << std::endl;
// start listening again
socket_.async_receive_from(
boost::asio::buffer(data_recv_, max_length), sender_endpoint_, boost::bind(&Flashlight::handle_receive_from, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
);
}
}
void Flashlight::handle_send_to(const boost::system::error_code& error, size_t bytes_sent) {
socket_.async_send_to(
boost::asio::buffer(data_sent_, bytes_sent), sender_endpoint_, boost::bind(&Flashlight::handle_send_to, this,
boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred)
);
}
I can't spot what I am missing. Some idea?
UPDATE: added orbslam3.hpp and orbslam3.cpp
#ifndef ORBSLAM3_H
#define ORBSLAM3_H
#include <algorithm>
#include <fstream>
#include <chrono>
#include <opencv2/core/core.hpp>
#include <cstdlib>
#include <iostream>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/thread/locks.hpp>
#include "flashlight.hpp"
// ==============================
// IMPORTANT: Don NOT move up the
// ========== following include !
#include <System.h>
class ORBSLAM3 {
public:
ORBSLAM3(string &sensor_type, string &vocab_path, string &settings_path, uint16_t cam_width, uint16_t cam_height);
int loop();
void pause();
void resume();
void reset();
void setMode(bool mapping); // false := localization only, true := localization+mapping
void saveMap();
void loadMap();
void shutdown();
private:
string sensor_type; // types = {"mono", "stereo", "rgbd")
string vocab_path; // path to the vocabulary (*.bin/*.txt)
string settings_path; // patch to the settings file (*.yaml)
uint16_t cam_width; // horizontal camera resolution
uint16_t cam_height; // vertical camera resolution
ORB_SLAM2::System *slam; // main orbslam system
cv::VideoCapture *cap1; // first camera capture devices
cv::VideoCapture *cap2; // second camera capture devices
cv::Mat img_left, img_right; // stereo images captured
cv::Mat tcw; // pose output information
};
#endif
And the implementation file orbslam3.cpp:
#include "orbslam3.hpp"
using namespace std;
ORBSLAM3::ORBSLAM3(string &sensor_type, string &vocab_path, string &settings_path, uint16_t cam_width, uint16_t cam_height) {
// assign arguments to local fields
this->sensor_type = sensor_type;
this->vocab_path = vocab_path;
this->settings_path = settings_path;
this->cam_width = cam_width;
this->cam_height = cam_height;
// initialize ORBSLAM system
if(sensor_type.compare("mono")==0) {
this->slam = new ORB_SLAM2::System(vocab_path, settings_path, ORB_SLAM2::System::MONOCULAR, true, true);
} else if(sensor_type.compare("stereo")==0) {
this->slam = new ORB_SLAM2::System(vocab_path, settings_path, ORB_SLAM2::System::STEREO, true, true);
} else if(sensor_type.compare("rgbd")==0) {
this->slam = new ORB_SLAM2::System(vocab_path, settings_path, ORB_SLAM2::System::RGBD, true, true);
} else {
std::cout << "ERROR: Unknown sensor type: " << sensor_type << std::endl;
}
// initialize cameras
cap1 = new cv::VideoCapture(0);
cap2 = new cv::VideoCapture(1);
// set camera resolutions
cap1->set(CV_CAP_PROP_FRAME_WIDTH, cam_width);
cap1->set(CV_CAP_PROP_FRAME_HEIGHT, cam_height);
cap2->set(CV_CAP_PROP_FRAME_WIDTH, cam_width);
cap2->set(CV_CAP_PROP_FRAME_HEIGHT, cam_height);
}
int ORBSLAM3::loop() {
// capture left and right images
cap1->read(img_right);
cap2->read(img_left);
// convert to b/w
//cv::cvtColor(imRight, imRight, CV_BGR2GRAY);
//cv::cvtColor(imLeft, imLeft, CV_BGR2GRAY);
// check image validity
if(img_left.empty()) {
cerr << endl << "Failed to capture left image." << endl;
return 1;
}
if(img_right.empty()) {
cerr << endl << "Failed to capture right image." << endl;
return 1;
}
// time
__int64 cnow = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// pass the images to the SLAM system
tcw = slam->TrackStereo(img_left, img_right, cnow / 1000.0);
// visualize stereo images
cv::imshow("Left Image", img_left);
cv::imshow("Right Image", img_right);
}
void ORBSLAM3::pause() {
}
void ORBSLAM3::resume() {
}
void ORBSLAM3::reset() {
}
void ORBSLAM3::setMode(bool mapping) {
}
void ORBSLAM3::saveMap() {
}
void ORBSLAM3::loadMap() {
}
void ORBSLAM3::shutdown() {
slam->Shutdown();
cap1->release();
cap2->release();
}
Looks like you have a circular dependency.
Fix that and it should work.
flashlight.hpp
// Remove this line.
// #include "orbslam3.hpp"
// Add a forward declaration.
// Unless you need the full declaration you should not be including the header file
// Prefer to use forward declarations when you are just using a pointer.
class ORBSLAM3;
flashlight.cpp
#include "flashlight.hpp"
// Add this line.
// You will probably need the actual definition if you use it in the code.
#include "orbslam3.hpp"
orbslam3.hpp
// Does not even look you need this in the header file.
// Remove headers you don't need.
// #include "flashlight.hpp"
We've made good progress in getting GRPC running under RHEL 7.
Our application has one rather complicated structure with three levels of nesting with the outer level implementing a "oneof" keyword.
We find that all our other structures run fine, but this one gives us an RPC failure with code=14.
We've simplified this part of the application as much as possible so it can hopefully be recompiled and run easily.
Here's the .proto file, updated to accommodate Uli's question:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.debug";
option java_outer_classname = "DebugProto";
option objc_class_prefix = "DEBUG";
package DEBUGpackage;
service DEBUGservice {
rpc DEBUG_val_container_get (input_int32_request) returns (outer_container) {}
}
message input_int32_request {
int32 ival = 1;
}
message inner_container {
repeated uint32 val_array = 1;
}
message middle_container {
inner_container vac = 1;
}
message other_container {
int32 other_val = 1;
}
message outer_container {
oneof reply {
middle_container r1 = 1;
other_container r2 = 2;
}
}
(Please note that the java lines in this prototype code are just in there because they are in the GRPC website examples. Our code is entirely C++, with no java. Don't know if that means we can do without some of these "option java..." lines).
Here's our client source code:
#include <iostream>
#include <memory>
#include <string>
#include <grpc++/grpc++.h>
#include <grpc/support/log.h>
#include <thread>
#include <unistd.h>
#include "debug.grpc.pb.h"
using grpc::Channel;
using grpc::ClientAsyncResponseReader;
using grpc::ClientContext;
using grpc::CompletionQueue;
using grpc::Status;
using DEBUGpackage::input_int32_request;
using DEBUGpackage::inner_container;
using DEBUGpackage::middle_container;
using DEBUGpackage::outer_container;
using DEBUGpackage::DEBUGservice;
class DEBUGClient {
public:
explicit DEBUGClient(std::shared_ptr<Channel> channel)
: stub_(DEBUGservice::NewStub(channel)) {}
void DEBUG_val_container_get() {
std::cout << "in DEBUG_val_container_get" << std::endl;
// Data we are sending to the server
input_int32_request val;
val.set_ival(0);
AsyncClientCall* call = new AsyncClientCall;
call->response_reader = stub_->AsyncDEBUG_val_container_get(&call->context, val, &cq_);
call->response_reader->Finish(&call->reply_, &call->status, (void*)call);
}
void AsyncCompleteRpc() {
void* got_tag;
bool ok = false;
while (cq_.Next(&got_tag, &ok)) {
AsyncClientCall* call = static_cast<AsyncClientCall*>(got_tag);
GPR_ASSERT(ok);
if (call->status.ok()) {
if (call->reply_.has_r1()) {
std::cout << call << " DEBUG received: "
<< call->reply_.r1().vac().val_array(0) << std::endl;
}
}
else {
std::cout << call << " RPC failed" << std::endl;
std::cout << " RPC failure code = " << call->status.error_code() << std::endl;
std::cout << " RPC failure message = " << call->status.error_message() << std::endl;
}
delete call;
}
}
private:
struct AsyncClientCall {
outer_container reply_;
ClientContext context;
Status status;
std::unique_ptr<ClientAsyncResponseReader<outer_container>> response_reader;
};
std::unique_ptr<DEBUGservice::Stub> stub_;
CompletionQueue cq_;
};
int main(int argc, char** argv) {
DEBUGClient DEBUG0(grpc::CreateChannel("172.16.17.46:50050", grpc::InsecureChannelCredentials()));
std::thread thread0_ = std::thread(&DEBUGClient::AsyncCompleteRpc, &DEBUG0);
DEBUG0.DEBUG_val_container_get();
sleep(1);
std::cout << "Press control-c to quit" << std::endl << std::endl;
thread0_.join(); //blocks forever
return 0;
}
And, here's our server source code:
#include <memory>
#include <iostream>
#include <string>
#include <thread>
#include <grpc++/grpc++.h>
#include <grpc/support/log.h>
#include "debug.grpc.pb.h"
#include <time.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
using grpc::Server;
using grpc::ServerAsyncResponseWriter;
using grpc::ServerBuilder;
using grpc::ServerContext;
using grpc::ServerCompletionQueue;
using grpc::Status;
using DEBUGpackage::inner_container;
using DEBUGpackage::input_int32_request;
using DEBUGpackage::middle_container;
using DEBUGpackage::outer_container;
using DEBUGpackage::DEBUGservice;
std::string save_server_address;
class ServerImpl final {
public:
~ServerImpl() {
server_->Shutdown();
cq_->Shutdown();
}
void Run() {
std::string server_address("0.0.0.0:50050");
ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&service_);
cq_ = builder.AddCompletionQueue();
server_ = builder.BuildAndStart();
std::cout << "Server listening on " << server_address << std::endl;
save_server_address = server_address;
HandleRpcs();
}
private:
class CallData {
public:
virtual void Proceed() = 0;
};
class DebugGetCallData final : public CallData{
public:
DebugGetCallData(DEBUGservice::AsyncService* service, ServerCompletionQueue* cq)
: service_(service), cq_(cq), responder_(&ctx_), status_(CREATE) {
Proceed();
}
void Proceed() {
if (status_ == CREATE) {
status_ = PROCESS;
service_->RequestDEBUG_val_container_get(&ctx_, &request_, &responder_, cq_, cq_, this);
} else if (status_ == PROCESS) {
new DebugGetCallData(service_, cq_);
char *portchar;
portchar = (char *) save_server_address.c_str();
long cq_addr = (long) cq_;
int cq_addr32 = (int) (cq_addr & 0xfffffff);
srand(cq_addr32);
fprintf(stderr, "%s task started\n", portchar); fflush(stderr);
unsigned int return_val = 10;
inner_container ic;
ic.add_val_array(return_val);
middle_container reply_temp;
reply_temp.set_allocated_vac(&ic);
reply_.set_allocated_r1(&reply_temp);
fprintf(stderr, "%s %s task done\n", portchar, "val_container_get"); fflush(stderr);
status_ = FINISH;
responder_.Finish(reply_, Status::OK, this);
} else {
GPR_ASSERT(status_ == FINISH);
}
}
private:
DEBUGservice::AsyncService* service_;
ServerCompletionQueue* cq_;
ServerContext ctx_;
input_int32_request request_;
outer_container reply_;
ServerAsyncResponseWriter<outer_container> responder_;
enum CallStatus { CREATE, PROCESS, FINISH };
CallStatus status_;
};
void HandleRpcs() {
new DebugGetCallData(&service_, cq_.get());
void* tag;
bool ok;
while (true) {
GPR_ASSERT(cq_->Next(&tag, &ok));
GPR_ASSERT(ok);
static_cast<CallData*>(tag)->Proceed();
}
}
std::unique_ptr<ServerCompletionQueue> cq_;
DEBUGservice::AsyncService service_;
std::unique_ptr<Server> server_;
};
int main() {
ServerImpl server;
server.Run();
return 0;
}
The output when I run it looks like this:
[fossum#netsres46 debug]$ DEBUG_client2
in DEBUG_val_container_get
0xb73ff0 RPC failed
RPC failure code = 14
RPC failure message = Endpoint read failed
Press control-c to quit
We ran the server under gdb, and found a place in the generated
file "debug.pb.cc" where if we just comment out one line, it all starts working.
Here's the pertinent piece of the generated file "debug.pb.cc":
middle_container::~middle_container() {
// ##protoc_insertion_point(destructor:DEBUGpackage.middle_container)
SharedDtor();
}
void middle_container::SharedDtor() {
if (this != internal_default_instance()) {
delete vac_; // comment out this one line, to make the problem go away
}
}
The "delete vac_" line appears to be an attempt to delete storage that either has already been deleted, or is about to be deleted somewhere else. Please, can someone look into this? [The files below are still the files we use to generate this code, and to debug the problem to this point]
I have no idea whether I've uncovered a bug in GRPC, or whether I've coded something wrong.
The issue is that you are allocated middle_container reply_tmp on the stack in your server. As a result it gets destructed as soon as you pass out of the scope. At that time, you have called Finish but not yet waited for its result. Since this is an async server, the data must remain alive until you've received the tag back for it. This is why manually editing your destructor works in your case; you're basically nullifying the destructor (and leaking memory as a result).
Below is my code, my problem is that readEvent() function never gets called.
Header file
class MyServer
{
public :
MyServer(MFCPacketWriter *writer_);
~MyServer();
void startReading();
void stopReading();
private :
MFCPacketWriter *writer;
pthread_t serverThread;
bool stopThread;
static void *readEvent(void *);
};
CPP file
MyServer::MyServer(MFCPacketWriter *writer_):writer(writer_)
{
serverThread = NULL;
stopThread = false;
LOGD(">>>>>>>>>>>>> constructed MyServer ");
}
MyServer::~MyServer()
{
writer = NULL;
stopThread = true;
}
void MyServer::startReading()
{
LOGD(">>>>>>>>>>>>> start reading");
if(pthread_create(&serverThread,NULL,&MyServer::readEvent, this) < 0)
{
LOGI(">>>>>>>>>>>>> Error while creating thread");
}
}
void *MyServer::readEvent(void *voidptr)
{
// this log never gets called
LOGD(">>>>>>>>>>>>> readEvent");
while(!MyServer->stopThread){
//loop logic
}
}
Another class
MyServer MyServer(packet_writer);
MyServer.startReading();
Since you are not calling pthread_join, your main thread is terminating without waiting for your worker thread to finish.
Here is a simplified example that reproduces the problem:
#include <iostream>
#include <pthread.h>
class Example {
public:
Example () : thread_() {
int rcode = pthread_create(&thread_, nullptr, Example::task, nullptr);
if (rcode != 0) {
std::cout << "pthread_create failed. Return code: " << rcode << std::endl;
}
}
static void * task (void *) {
std::cout << "Running task." << std::endl;
return nullptr;
}
private:
pthread_t thread_;
};
int main () {
Example example;
}
View Results
No output is produced when running this program, even though pthread_create was successfully called with Example::task as the function parameter.
This can be fixed by calling pthread_join on the thread:
#include <iostream>
#include <pthread.h>
class Example {
public:
Example () : thread_() {
int rcode = pthread_create(&thread_, nullptr, Example::task, nullptr);
if (rcode != 0) {
std::cout << "pthread_create failed. Return code: " << rcode << std::endl;
}
}
/* New code below this point. */
~Example () {
int rcode = pthread_join(thread_, nullptr);
if (rcode != 0) {
std::cout << "pthread_join failed. Return code: " << rcode << std::endl;
}
}
/* New code above this point. */
static void * task (void *) {
std::cout << "Running task." << std::endl;
return nullptr;
}
private:
pthread_t thread_;
};
int main () {
Example example;
}
View Results
Now the program produces the expected output:
Running task.
In your case, you could add a call to pthread_join to the destructor of your MyServer class.
I'm trying to detect lost connections that closed without sending the close frame by sending pings on a websocket++ application.
I'm having trouble setting up the handler.
I initially tried to set it up like how the handlers are setup with the broadcast_server example:
m_server.set_ping_handler(bind(&broadcast_server::on_m_server_ping,this,::_1,::_2));
That gives this error:
note: candidate is:
websocketpp/endpoint.hpp:240:10: note: void websocketpp::endpoint::set_ping_handler(websocketpp::ping_handler) [with connection = websocketpp::connection; config = websocketpp::config::asio_tls_client; websocketpp::ping_handler = std::function, std::basic_string)>]
void set_ping_handler(ping_handler h) {
I thought that setting up a typedef like with this problem would solve it, but putting it outside the class broadcast_server makes it impossible to access m_server.
How can this handler be properly implemented?
Includes & flags
Boost 1.54
#include <websocketpp/config/asio.hpp>
#include <websocketpp/server.hpp>
#include <websocketpp/common/thread.hpp>
typedef websocketpp::server<websocketpp::config::asio_tls> server;
flags
-std=c++0x -I ~/broadcast_server -D_WEBSOCKETPP_CPP11_STL_
-D_WEBSOCKETPP_NO_CPP11_REGEX_ -lboost_regex -lboost_system
-lssl -lcrypto -pthread -lboost_thread
typedef
typedef websocketpp::lib::function<bool(connection_hdl,std::string)> ping_handler;
Solving quite easy. First, the definition in websocket/connection.hpp:
/// The type and function signature of a ping handler
/**
* The ping handler is called when the connection receives a WebSocket ping
* control frame. The string argument contains the ping payload. The payload is
* a binary string up to 126 bytes in length. The ping handler returns a bool,
* true if a pong response should be sent, false if the pong response should be
* suppressed.
*/
typedef lib::function<bool(connection_hdl,std::string)> ping_handler;
gives the basic idea that function must have the definition:
bool on_ping(connection_hdl hdl, std::string s)
{
/* Do something */
return true;
}
Now everything comes to the right place:
m_server.set_ping_handler(bind(&broadcast_server::on_ping,this,::_1,::_2));
The complete modified example source looks like:
#include <websocketpp/config/asio_no_tls.hpp>
#include <websocketpp/server.hpp>
#include <iostream>
/*#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>*/
#include <websocketpp/common/thread.hpp>
typedef websocketpp::server<websocketpp::config::asio> server;
using websocketpp::connection_hdl;
using websocketpp::lib::placeholders::_1;
using websocketpp::lib::placeholders::_2;
using websocketpp::lib::bind;
using websocketpp::lib::thread;
using websocketpp::lib::mutex;
using websocketpp::lib::unique_lock;
using websocketpp::lib::condition_variable;
/* on_open insert connection_hdl into channel
* on_close remove connection_hdl from channel
* on_message queue send to all channels
*/
enum action_type {
SUBSCRIBE,
UNSUBSCRIBE,
MESSAGE
};
struct action {
action(action_type t, connection_hdl h) : type(t), hdl(h) {}
action(action_type t, connection_hdl h, server::message_ptr m)
: type(t), hdl(h), msg(m) {}
action_type type;
websocketpp::connection_hdl hdl;
server::message_ptr msg;
};
class broadcast_server {
public:
broadcast_server() {
// Initialize Asio Transport
m_server.init_asio();
// Register handler callbacks
m_server.set_open_handler(bind(&broadcast_server::on_open,this,::_1));
m_server.set_close_handler(bind(&broadcast_server::on_close,this,::_1));
m_server.set_message_handler(bind(&broadcast_server::on_message,this,::_1,::_2));
m_server.set_ping_handler(bind(&broadcast_server::on_ping,this,::_1,::_2));
}
void run(uint16_t port) {
// listen on specified port
m_server.listen(port);
// Start the server accept loop
m_server.start_accept();
// Start the ASIO io_service run loop
try {
m_server.run();
} catch (const std::exception & e) {
std::cout << e.what() << std::endl;
} catch (websocketpp::lib::error_code e) {
std::cout << e.message() << std::endl;
} catch (...) {
std::cout << "other exception" << std::endl;
}
}
void on_open(connection_hdl hdl) {
unique_lock<mutex> lock(m_action_lock);
//std::cout << "on_open" << std::endl;
m_actions.push(action(SUBSCRIBE,hdl));
lock.unlock();
m_action_cond.notify_one();
}
void on_close(connection_hdl hdl) {
unique_lock<mutex> lock(m_action_lock);
//std::cout << "on_close" << std::endl;
m_actions.push(action(UNSUBSCRIBE,hdl));
lock.unlock();
m_action_cond.notify_one();
}
void on_message(connection_hdl hdl, server::message_ptr msg) {
// queue message up for sending by processing thread
unique_lock<mutex> lock(m_action_lock);
//std::cout << "on_message" << std::endl;
m_actions.push(action(MESSAGE,hdl,msg));
lock.unlock();
m_action_cond.notify_one();
}
bool on_ping(connection_hdl hdl, std::string s)
{
/* Do something */
return true;
}
void process_messages() {
while(1) {
unique_lock<mutex> lock(m_action_lock);
while(m_actions.empty()) {
m_action_cond.wait(lock);
}
action a = m_actions.front();
m_actions.pop();
lock.unlock();
if (a.type == SUBSCRIBE) {
unique_lock<mutex> con_lock(m_connection_lock);
m_connections.insert(a.hdl);
} else if (a.type == UNSUBSCRIBE) {
unique_lock<mutex> con_lock(m_connection_lock);
m_connections.erase(a.hdl);
} else if (a.type == MESSAGE) {
unique_lock<mutex> con_lock(m_connection_lock);
con_list::iterator it;
for (it = m_connections.begin(); it != m_connections.end(); ++it) {
m_server.send(*it,a.msg);
}
} else {
// undefined.
}
}
}
private:
typedef std::set<connection_hdl,std::owner_less<connection_hdl>> con_list;
server m_server;
con_list m_connections;
std::queue<action> m_actions;
mutex m_action_lock;
mutex m_connection_lock;
condition_variable m_action_cond;
};
int main() {
try {
broadcast_server server_instance;
// Start a thread to run the processing loop
thread t(bind(&broadcast_server::process_messages,&server_instance));
// Run the asio loop with the main thread
server_instance.run(9002);
t.join();
} catch (std::exception & e) {
std::cout << e.what() << std::endl;
}
}