Boost blocking TCP implementation taken from here:
http://www.boost.org/doc/libs/1_52_0/doc/html/boost_asio/example/timeouts/blocking_tcp_client.cpp
Another similar problem, mentioned here
Boost.Asio segfault, no idea why
I tried checking the destructor order and dependencies as mentioned in the answer but no luck.
Posting relevant code here
edit:: This MSVC code actually works without segmentation fault. Will be updating code with more relevant info from the failing program.
main.cpp
{
int main(void) {
int k = Connection_Init();
return k;
}
}
In Connection_Init(), I am calling c.connect(IP, Host, timeout);
The seg fault occurs while returning from c.connect(), given in Network.cpp
Network.h
{
class client
{
public:
client()
: socket_(io_service_),
deadline_(io_service_)
{
// No deadline is required until the first socket operation is started. We
// set the deadline to positive infinity so that the actor takes no action
// until a specific deadline is set.
deadline_.expires_at(boost::posix_time::pos_infin);
// Start the persistent actor that checks for deadline expiry.
check_deadline();
}
int connect(const std::string& host, const std::string& service, tcp::resolver::query& q1,
boost::posix_time::time_duration timeout)
{
// Resolve the host name and service to a list of endpoints.
//tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(q1);
// Set a deadline for the asynchronous operation. As a host name may
// resolve to multiple endpoints, this function uses the composed operation
// async_connect. The deadline applies to the entire operation, rather than
// individual connection attempts.
deadline_.expires_from_now(timeout);
// Set up the variable that receives the result of the asynchronous
// operation. The error code is set to would_block to signal that the
// operation is incomplete. Asio guarantees that its asynchronous
// operations will never fail with would_block, so any other value in
// ec indicates completion.
boost::system::error_code ec = boost::asio::error::would_block;
// Start the asynchronous operation itself. The boost::lambda function
// object is used as a callback and will update the ec variable when the
// operation completes. The blocking_udp_client.cpp example shows how you
// can use boost::bind rather than boost::lambda.
boost::asio::async_connect(socket_, iter, var(ec) = _1);
// Block until the asynchronous operation has completed.
do io_service_.run_one(); while (ec == boost::asio::error::would_block);
// Determine whether a connection was successfully established. The
// deadline actor may have had a chance to run and close our socket, even
// though the connect operation notionally succeeded. Therefore we must
// check whether the socket is still open before deciding if we succeeded
// or failed.
if (ec || !socket_.is_open()) {
cout << "send_test_case:connect: Connection could not be established to"
<< LWIP_IP << " " << LWIP_PORT << endl;
//throw boost::system::system_error(
//boost::asio::error::operation_aborted);
//ec ? ec : boost::asio::error::operation_aborted);
return -1;
}
return 1;
}
private:
void check_deadline(
boost::asio::io_service io_service_;
//moving to public access
public: tcp::socket socket_;
private: deadline_timer deadline_;
boost::asio::streambuf input_buffer_;
};
}
and Network.cpp
{
client c;
tcp::resolver::query query(LWIP_IP, LWIP_PORT);
int Connection_Init() {
cout << "IP: " << LWIP_IP << "and Port:" << LWIP_PORT << endl;
int status = 1;
try
{
status = c.connect(LWIP_IP, LWIP_PORT, query, boost::posix_time::seconds(POSITIVE_TESTING_CONNECT_TIMEOUT));
}
//connection initialization should never fail
catch(std::exception &e) {
status = -1;
std::cerr << __FUNCTION__ << ": " << "Exception: " << e.what() << "\n";
}
catch(...) {
status = -1;
}
return status;
}
}
Related
I'm converting an application from using Juce asynchronous i/o to asio. The first part is to rewrite the code that receives traffic from another application on the same machine (it's a Lightroom Lua plugin that sends \n delimited messages on port 58764). Whenever I successfully connect to that port with my C++ program, I get a series of error codes, all the same:
An operation on a socket could not be performed because the system lacked sufficient buffer space or because a queue was full.
Can someone point out my error? I can see that the socket is successfully opened. I've reduced this from my full program to a minimal example. I also tried it with connect instead of async_connect and had the same problem.
#include <iostream>
#include "asio.hpp"
asio::io_context io_context_;
asio::ip::tcp::socket socket_{io_context_};
void loop_me()
{
asio::streambuf streambuf{};
while (true) {
if (!socket_.is_open()) {
return;
}
else {
asio::async_read_until(socket_, streambuf, '\n',
[&streambuf](const asio::error_code& error_code, std::size_t bytes_transferred) {
if (error_code) {
std::cerr << "Socket error " << error_code.message() << std::endl;
return;
}
// Extract up to the first delimiter.
std::string command{buffers_begin(streambuf.data()),
buffers_begin(streambuf.data()) + bytes_transferred};
std::cout << command << std::endl;
streambuf.consume(bytes_transferred);
});
}
}
}
int main()
{
auto work_{asio::make_work_guard(io_context_)};
std::thread io_thread_;
std::thread run_thread_;
io_thread_ = std::thread([] { io_context_.run(); });
socket_.async_connect(asio::ip::tcp::endpoint(asio::ip::address_v4::loopback(), 58764),
[&run_thread_](const asio::error_code& error) {
if (!error) {
std::cout << "Socket connected in LR_IPC_In\n";
run_thread_ = std::thread(loop_me);
}
else {
std::cerr << "LR_IPC_In socket connect failed " << error.message() << std::endl;
}
});
std::this_thread::sleep_for(std::chrono::seconds(1));
socket_.close();
io_context_.stop();
if (io_thread_.joinable())
io_thread_.join();
if (run_thread_.joinable())
run_thread_.join();
}
You are trying to start an infinite number of asynchronous read operations at the same time. You shouldn't start a new asynchronous read until the previous one finished.
async_read_until returns immediately, even though the data hasn't been received yet. That's the point of "async".
I have two objects A and B. A uses B underneath, which is a tcp client object. Object B is created in a separate thread in object A's constructor. Within the constructor for B, I use Boost Asio for socket and a deadline timer. I used async calls for the socket connect and the wait on the timer. Here is the code for object B's constructor:
B::B(const boost::asio::ip::address& ipaddr,
std::uint16_t port) : io_service_(),
socket_(io_service_),
endpoint_(ipaddr, port),
connected_(false) {
boost::asio::deadline_timer dt(io_service_);
socket_.async_connect(endpoint_, [this, &dt](const boost::system::error_code& ec) {
if (ec) {
std::cout << ec.message() << std::endl;
}
else {
dt.cancel();
std::cout << "Connected before timer expired" << std::endl;
connected_ = true;
socket_.set_option(boost::asio::socket_base::keep_alive(true));
}
});
dt.expires_from_now(boost::posix_time::seconds(3));
dt.async_wait([this](const boost::system::error_code& ec) {
if (ec) {
std::cout << ec.message() << std::endl;
}
else {
std::cout << "Timer expired before connection" << std::endl;
io_service_.stop();
}
});
io_service_.run();
}
When the machine the tcp client wants to connect to is in the ON state, it works. When the machine is in the OFF state, the expectation is that the deadline timer will expire in 3 seconds and the connection flag will not be set. I am getting an abort call during execution. I am sure it is something with the deadline timer, but cannot pin down exactly what.
Does anyone see what may be wrong here or have any other suggestions? Is there something I am missing with Boost Deadline Timer?
As the title says i have a question concerning the following scenario (simplyfied example):
Assume that i have an object of the Generator-Class below, which continuously updates its dataChunk member ( running in the main thread).
class Generator
{
void generateData();
uint8_t dataChunk[999];
}
Furthermore i have an async. acceptor of TCP-connections to which 1-N clients can connect to (running in a second thread).
The acceptor starts a new thread for each new client-connection, in which an object of the Connection class below, receives a request message from the client and provides a fraction of the dataChunk (belonging to the Generator) as an answer. Then waits for a new request and so on...
class Connection
{
void setDataChunk(uint8_t* dataChunk);
void handleRequest();
uint8_t* dataChunk;
}
Finally the actual question: The desired behaviour is that the Generator object generates a new dataChunk and waits until all 1-N Connection objects have delt with their client requests until it generates a new dataChunk.
How do i lock the dataChunk for writing access of the Generator object while the Connection objects deal with their requests, but all Connection objects in their respective threads are supposed to have reading-access at the same time during their request-handling phase.
On the other hand the Connection objects are supposed to wait for a new dataChunk after dealing with their respective request, without dropping a new client request.
--> I think a single mutex won't do the trick here.
My first idea was to share a struct between the objects with a semaphore for the Generator and a vector of semaphores for the connections. With these, every object could "understand" the state of the full-system and work accordingly.
What to you guys think, what is best practice i cases like this?
Thanks in advance!
There are several ways to solve it.
You can use std::shared_mutex.
void Connection::handleRequest()
{
while(true)
{
std::shared_lock<std::shared_mutex> lock(GeneratorObj.shared_mutex);
if(GeneratorObj.DataIsAvailable()) // we need to know that data is available
{
// Send to client
break;
}
}
}
void Generator::generateData()
{
std::unique_lock<std::shared_mutex> lock(GeneratorObj.shared_mutex);
// Generate data
}
Or you can use a boost::lockfree::queue, but data structures will be different.
How do i lock the dataChunk for writing access of the Generator object while the Connection objects deal with their requests, but all Connection objects in their respective threads are supposed to have reading-access at the same time during their request-handling phase.
I'd make a logical chain of operations, that includes the generation.
Here's a sample:
it is completely single threaded
accepts unbounded connections and deals with dropped connections
it uses a deadline_timer object to signal a barrier when waiting for to send of a chunck to (many) connections. This makes it convenient to put the generateData call in an async call chain.
Live On Coliru
#include <boost/asio.hpp>
#include <list>
#include <iostream>
namespace ba = boost::asio;
using ba::ip::tcp;
using boost::system::error_code;
using Clock = std::chrono::high_resolution_clock;
using Duration = Clock::duration;
using namespace std::chrono_literals;
struct Generator {
void generateData();
uint8_t dataChunk[999];
};
struct Server {
Server(unsigned short port) : _port(port) {
_barrier.expires_at(boost::posix_time::neg_infin);
_acc.set_option(tcp::acceptor::reuse_address());
accept_loop();
}
void generate_loop() {
assert(n_sending == 0);
garbage_collect(); // remove dead connections, don't interfere with sending
if (_socks.empty()) {
std::clog << "No more connections; pausing Generator\n";
} else {
_gen.generateData();
_barrier.expires_at(boost::posix_time::pos_infin);
for (auto& s : _socks) {
++n_sending;
ba::async_write(s, ba::buffer(_gen.dataChunk), [this,&s](error_code ec, size_t written) {
assert(n_sending);
--n_sending; // even if failed, decreases pending operation
if (ec) {
std::cerr << "Write: " << ec.message() << "\n";
s.close();
}
std::clog << "Written: " << written << ", " << n_sending << " to go\n";
if (!n_sending) {
// green light to generate next chunk
_barrier.expires_at(boost::posix_time::neg_infin);
}
});
}
_barrier.async_wait([this](error_code ec) {
if (ec && ec != ba::error::operation_aborted)
std::cerr << "Client activity: " << ec.message() << "\n";
else generate_loop();
});
}
}
void accept_loop() {
_acc.async_accept(_accepting, [this](error_code ec) {
if (ec) {
std::cerr << "Accept fail: " << ec.message() << "\n";
} else {
std::clog << "Accepted: " << _accepting.remote_endpoint() << "\n";
_socks.push_back(std::move(_accepting));
if (_socks.size() == 1) // first connection?
generate_loop(); // start generator
accept_loop();
}
});
}
void run_for(Duration d) {
_svc.run_for(d);
}
void garbage_collect() {
_socks.remove_if([](tcp::socket& s) { return !s.is_open(); });
}
private:
ba::io_service _svc;
unsigned short _port;
tcp::acceptor _acc { _svc, { {}, _port } };
tcp::socket _accepting {_svc};
std::list<tcp::socket> _socks;
Generator _gen;
size_t n_sending = 0;
ba::deadline_timer _barrier {_svc};
};
int main() {
Server s(6767);
s.run_for(3s); // COLIRU
}
#include <fstream>
// synchronously generate random data chunks
void Generator::generateData() {
std::ifstream ifs("/dev/urandom", std::ios::binary);
ifs.read(reinterpret_cast<char*>(dataChunk), sizeof(dataChunk));
std::clog << "Generated chunk: " << ifs.gcount() << "\n";
}
Prints (for just the 1 client):
Accepted: 127.0.0.1:60870
Generated chunk: 999
Written: 999, 0 to go
Generated chunk: 999
[... snip ~4000 lines ...]
Written: 999, 0 to go
Generated chunk: 999
Write: Broken pipe
Written: 0, 0 to go
No more connections; pausing Generator
While deleting an SSLSocket after a successful connection is made and used I am getting an access violation
Unhandled exception at 0x770f32d0 in Application_client_example.exe: 0xC0000005: Access violation reading location 0x00000dd3c0c76c48.
The access violation is coming from this part of the boost code:
engine::~engine()
{
if (SSL_get_app_data(ssl_))
{
delete static_cast<verify_callback_base*>(SSL_get_app_data(ssl_));
SSL_set_app_data(ssl_, 0);
}
::BIO_free(ext_bio_);
::SSL_free(ssl_);
}
This code worked in boost version 1.47. The only changes I have made is I updated the boost libraries to the current version 1.53 and built a 64 bit version of the library and exe.
Here is the SSL connection that is created and deleted:
// Connect
SSLSocket* socket = new SSLSocket();
if ((errorCode = socket->connect((char*)server.c_str(), (char*)port.c_str())) != 0)
{
Logger::log(log4cpp::Priority::FATAL, "Secure Socket Error");
return errorCode;
}
delete socket
Here is the SSLSocket destructor
SSLSocket::~SSLSocket(void)
{
try {
sslSocket->shutdown();
delete sslSocket;
}
catch (std::exception& e)
{
std::string exception(e.what());
Logger::log(log4cpp::Priority::FATAL, "[SSLSocket] Error deleting sslSocket. Exception: " + exception);
}
}
Here is the def for SSLSocket. SSLSocket is essentially just a wrapper class for the ssl socket:
#ifndef __SSLSOCKET__
#define __SSLSOCKET__
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/array.hpp>
#include <boost/asio/ssl.hpp>
#include <string>
#include "Logger.h"
#include "Config.h"
using namespace boost::asio;
class SSLSocket
{
private:
io_service io_service;
ssl::stream<ip::tcp::socket>* sslSocket;
public:
SSLSocket(void);
~SSLSocket(void);
DWORD connect(char* remoteServer, char* remotePort);
DWORD sendString(std::string data);
std::string receiveString(void);
};
#endif
Here is my code that I use to shut down the socket connection in my SSLSockets class, which is also a wrapper around ASIO for an SSL connection. I am using Boost ASIO version 1.52 for Windows with 32 bit libraries. I too used to receive an exception when shutting down the socket until I discovered how to do it properly:
void SSLSocket::Stop()
{
// This method calls the shutdown method on the socket in order to stop reads or writes that might be going on. If this is not done, then an exception will be thrown
// when it comes time to delete this object.
//
boost::system::error_code EC;
try
{
// This method can be called from the handler as well. So once the ShuttingDown flag is set, don't go throught the same code again.
if (ShuttingDown)
return;
LockCode->Acquire(); // Single thread the code.
// Only do this once.
if (!ShuttingDown)
{
ShuttingDown = true;
pSocket->next_layer().cancel();
pSocket->shutdown(EC);
// Note that EC will usually have an error condition, but it does not seem to be a problem.
delete pSocket;
pSocket = 0;
ReqAlive = false;
SetEvent(hEvent);
IOService->stop();
LobbySocketOpen = false;
// Wait until the 2 threads have exited before returning.
WorkerThreads.join_all();
}
LockCode->Release();
delete LockCode;
LockCode = 0;
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::Stop: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
}
In answer to question about the Lock variable
Lock is a class that encapsulates a critical section (specific to Microsoft) so that the code can be single threaded. Here is the definition for it:
class Lock
{
public:
Lock()
{
::InitializeCriticalSection(&CS);
}
~Lock()
{
::DeleteCriticalSection(&CS);
}
void Acquire()
{
::EnterCriticalSection(&CS);
}
void Release()
{
::LeaveCriticalSection(&CS);
}
private:
Lock(const Lock&);
Lock& operator=(const Lock&);
CRITICAL_SECTION CS;
};
Socket Creation Code
This is the code I use to create the SSL context object and SSL socket object:
void SSLSocket::Connect(SSLSocket* psSLS, const string& serverPath, string& port)
{
// Connects to the server.
// serverPath - specifies the path to the server. Can be either an ip address or url.
// port - port server is listening on.
//
try
{
LockCode->Acquire(); // Single thread the code.
// If the user has tried to connect before, then make sure everything is clean before trying to do so again.
if (pSocket)
{
delete pSocket;
pSocket = 0;
}
// If serverPath is a URL, then resolve the address.
if ((serverPath[0] < '0') || (serverPath[0] > '9')) // Assumes that the first char of the server path is not a number when resolving to an ip addr.
{
// Create the resolver and query objects to resolve the host name in serverPath to an ip address.
boost::asio::ip::tcp::resolver resolver(*IOService);
boost::asio::ip::tcp::resolver::query query(serverPath, port);
boost::asio::ip::tcp::resolver::iterator EndpointIterator = resolver.resolve(query);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// The thread we are on now, is most likely the user interface thread. Create a thread to handle all incoming socket work messages.
// Only one thread is created to handle the socket I/O reading and another thread is created to handle writing.
if (!RcvThreadCreated)
{
WorkerThreads.create_thread(boost::bind(&SSLSocket::RcvWorkerThread, this));
RcvThreadCreated = true;
WorkerThreads.create_thread(boost::bind(&SSLSocket::SendWorkerThread, this));
}
// Try to connect to the server. Note - add timeout logic at some point.
boost::asio::async_connect(pSocket->lowest_layer(), EndpointIterator,
boost::bind(&SSLSocket::HandleConnect, this, boost::asio::placeholders::error));
}
else
{
// serverPath is an ip address, so try to connect using that.
//
stringstream ss1;
boost::system::error_code EC;
ss1 << "SSLSocket::Connect: Preparing to connect to game server " << serverPath << " : " << port << ".\n";
Log.LogString(ss1.str(), LogInfo);
// Create an endpoint with the specified ip address.
const boost::asio::ip::address IP(boost::asio::ip::address::from_string(serverPath));
int iport = atoi(port.c_str());
const boost::asio::ip::tcp::endpoint EP(IP, iport);
// Set up an SSL context.
boost::asio::ssl::context ctx(*IOService, boost::asio::ssl::context::tlsv1_client);
// Specify to not verify the server certificiate right now.
ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
// Init the socket object used to initially communicate with the server.
pSocket = new boost::asio::ssl::stream<boost::asio::ip::tcp::socket>(*IOService, ctx);
//
// Try to connect to the server. Note - add timeout logic at some point.
pSocket->next_layer().connect(EP, EC);
if (EC)
{
// Log an error. This worker thread should exit gracefully after this.
stringstream ss;
ss << "SSLSocket::Connect: connect failed to " << sClientIp << " : " << uiClientPort << ". Error: " << EC.message() + ".\n";
Log.LogString(ss.str(), LogError);
}
stringstream ss;
ss << "SSLSocket::Connect: Calling HandleConnect for game server " << serverPath << " : " << port << ".\n";
Log.LogString(ss.str(), LogInfo);
HandleConnect(EC);
}
}
catch (std::exception& e)
{
stringstream ss;
ss << "SSLSocket::Connect: threw an error - " << e.what() << ".\n";
Log.LogString(ss.str(), LogError);
Stop();
}
LockCode->Release();
}
Ok so the fix for this after searching around and not really finding anything related was that I was building all the boost libraries as MTd. I was assuming that I would use the MTd build for OpenSSL libraries but come to find out if you use the non MT Openssl libraries it works just fine.
I have two applications which work like a TCP client/server.
First application is the client which uses OpenCV to detect and send commands via TCP to the Server which controls a mobile robot.
My applications work well if I'm in my developing computer, but when I test it in real world with my robot, i realize that I have some delays with the data exchanged between client and server.
This happens because the computer where iItest the applications is a little bit slow compared to my developing computer which is faster and give no problems. In real world case, server doesn't receive packets from client in real time so it execute the operations with a delay.
So, the problem is when the client loose the detection and send commands to the server in order to stop it. The server receives packets with a delay so when clients sends stop (heading = 0, distance = 0, nodetection) server doesn't receive the command immediately because it is receiving previous command packets and so it stop only after few meters.
I'd like to find a solution in order to stop immediately the server and discard all the packages about the moving information because they are useless if the robot has to stop.
In order to stop the robot I send a nodetecting package which unfortunately is not received in real time so the robot continue to move for a while.
(I'm doing this test on the same machine, so I connect on localhost)
At the moment, client uses this code:
while (key_mode!='q')
{
//wait and error processing
context.WaitAnyUpdateAll();
// obtain al the metadata image,depthmap and scene
Mat frame = getImageFromKinect();
// do detection and tracking
switch(mode)
{
..
case ROBOT_CONTROL:
{
// Connect to the server
using boost::asio::ip::tcp;
boost::asio::io_service io_service;
tcp::resolver resolver(io_service);
tcp::resolver::query query(tcp::v4(), server, boost::lexical_cast<string>(porta));
tcp::resolver::iterator iterator = resolver.resolve(query);
tcp::socket s(io_service);
try
{
s.connect(*iterator);
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not connect to the server\n" << e.what() << "\nPossible Solution: try to check is Server is UP\n" << std::endl;
}
..
..
float delta = heading - last_heading;
if (!is_equal(delta, 0.0)){
// heading_data = send_heading + token + boost::lexical_cast<std::string>(delta);
// heading_length = strlen(heading_data.c_str());
try
{
// boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
}
last_heading = heading; // store current for next subtraction
#endif
#if 1
heading_scalato = heading / 3.0;
heading_data = send_heading + token + boost::lexical_cast<std::string>(heading_scalato);
heading_length = strlen(heading_data.c_str());
try
{
boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
#endif
distance_data = send_distance + token + boost::lexical_cast<std::string>(distance);
distance_length = strlen(distance_data.c_str());
try
{
boost::asio::write(s, boost::asio::buffer(distance_data, distance_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not connect : " << e.what() << std::endl;
}
..
..
// if it has to stop:
else
{
// stop rover
//control.setHeading(0.0);
//control.setDistance(0.0);
float heading = 0.0;
float distance = 0.0;
heading_data = send_heading + token + boost::lexical_cast<std::string>(heading);
distance_data = send_distance + token + boost::lexical_cast<std::string>(distance);
heading_length = heading_data.size();//strlen(heading_data.c_str());
distance_length = strlen(distance_data.c_str());
try
{
boost::asio::write(s, boost::asio::buffer(heading_data, heading_length));
boost::asio::write(s, boost::asio::buffer(distance_data, distance_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
// write info on image
char text[100];
sprintf(text,"ROBOT CONTROL: No detection");
putText(hogResultFrame,text,Point(4,89),FONT_HERSHEY_PLAIN,1,Scalar(0,0,0));
putText(hogResultFrame,text,Point(5,90),FONT_HERSHEY_PLAIN,1,Scalar(100,100,255));
nodetection_length = nodetection.size();
try
{
boost::asio::write(s, boost::asio::buffer(nodetection, nodetection_length));
}
catch (boost::system::system_error const& e)
{
std::cout << "Warning: could not send commands : " << e.what() << std::endl;
}
In server, i use:
void* runThread(void*)
{
while(Aria::getRunning())
{
if(start_routine){
if(temp_heading < 0.0){
printf("\n\nStarting Discovering routine, then sleeping 3 seconds.\a\n\n");
robot.setRotVel(5.0);
ArUtil::sleep(3000);
temp_heading = -1;
}
else if(temp_heading >= 0.0) {
printf("\n\nStarting Clockwise Discovering routine, then sleeping 3 seconds.\a\n\n");
robot.setRotVel(-5.0);
ArUtil::sleep(3000);
temp_heading = 1;
}
}
if( !flag_heading && !flag_distance)
{
myMutex.lock();
temp_heading=m_heading;
temp_distance=m_distance;
myMutex.unlock();
if (is_equal(temp_heading, 0.0)){
robot.setRotVel(0.0);
}
else robot.setRotVel(-ArMath::radToDeg(temp_heading));
if(temp_distance <= distanza_minima || is_equal(temp_distance, 0.0))
robot.setVel(0.0);
else
robot.setVel(float(temp_distance/20));
printf("runThread:: heading= %f distance = %f rob_vel = %f rob_rot_vel = %f\n",ArMath::radToDeg(temp_heading),temp_distance, robot.getVel(),robot.getRotVel());
flag_heading = true;
flag_distance = true;
start_routine = false;
}
ArUtil::sleep(100);
}
}
DataLine GetValueFromLine(const std::string& sData) {
std::string sName, sInteger;
std::stringstream ss;
DataLine Result;
size_t sz = sData.find('#');
sName = sData.substr(0,sz); // Just in case you need it later
Result.sName = sName;
sInteger = sData.substr(sz + 1,sData.length() - sz);
ss.str(sInteger);
ss >> Result.nNumber;
if (ss.fail()) {
// something went wrong, probably not an integer
}
return Result;
}
void session(socket_ptr sock)
{
try
{
for (;;)
{
char data[max_length];
boost::system::error_code error;
size_t length = sock->read_some(boost::asio::buffer(data), error);
data[length] = 0;
if (error == boost::asio::error::eof)
break; // Connection closed cleanly by peer.
else if (error)
throw boost::system::system_error(error); // Some other error.
output = GetValueFromLine(data);
std::cout << "*******************\n";
comando = output.sName;
valore = output.nNumber;
if (output.sName == "nodetection"){
start_routine = true;
std::cout << "\nSto ricevendo: " << output.sName;
}
else if (output.sName == "heading"){
start_routine = false;
control.setHeading(output.nNumber);
std::cout << "\nSto ricevendo: " << output.sName << "e heading: " << output.nNumber;
}
else if (output.sName == "distance"){
start_routine = false;
control.setDistance(output.nNumber);
std::cout << "\nSto ricevendo: " << output.sName << "e distance: " << output.nNumber;
}
// boost::asio::write(*sock, boost::asio::buffer(data, length));
}
}
catch (std::exception& e)
{
std::cerr << "Exception in thread: " << e.what() << "\n";
}
}
void server(boost::asio::io_service& io_service, short port)
{
tcp::acceptor a(io_service, tcp::endpoint(tcp::v4(), port));
for (;;)
{
socket_ptr sock(new tcp::socket(io_service));
a.accept(*sock);
boost::thread t(boost::bind(session, sock));
}
}
int main(int argc, char **argv)
{
// control server initialitation..
....
boost::asio::io_service io_service;
server(io_service, porta);
return 0;
}
I was thinking to force the client to close the TCP connection when it reaches a no detecting condition in order to force the server to reject the pending packets, but how I can do this?
How to destroy s pointer in boost?
Are there any other solutions?
If I close the connection, does the server reject the pending packets?
As I understand your problem, you have a message that you intend your application to abandon all current processing and flush the input queue. However, because the application is busy receiving and processing previous messages, it does not receive the abandon and flush message until all previous messages are processed - which makes abandon and flush a no operation
IMHO you need to design and code a multithreaded application.
One thread, as light weight as possible, reads the incoming messages as fast as possible and quickly checks for the abandon and flush message. If the message is OK, then it is added to a queue and the next message is checked.
The second thread pulls the messages from the queue where the messages are stored by the first thread and processes them, perhaps taking a long time to do so. From time time it checks for an abandon and flush signal from the first thread.
Another approach to consider: the application that sends the messages maintains the queue. When the application which receives the messages finishes processing a message, it sends a request for the next message. The sender only sends messages when requested. If the abandon and flush condition arises, the application sending the messages looks after this. The application receiving the messages only has to deal with one at a time. This approach greatly simplify the message receiver, at the cost of complexity in the sending application, a more elaborate communications protocol and, possibly, a reduction in maximum throughput.