I am trying to learn boost asio socket. there is one interesting example in boost web page which set a deadline time to monitor the timeout and change async io to sync io fashion. but when I remove the deadline timer the program stuck in while loop in write_line, I don't understand why the connection can be setup but the socket write is stuck. it seems that the writing never finished ,the handler never called so the "ec" never changed. Thank you in advance!!
#include <boost/asio/connect.hpp>
#include <boost/asio/deadline_timer.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <boost/asio/read_until.hpp>
#include <boost/asio/streambuf.hpp>
#include <boost/system/system_error.hpp>
#include <boost/asio/write.hpp>
#include <cstdlib>
#include <iostream>
#include <string>
#include <boost/bind.hpp>
using boost::asio::deadline_timer;
using boost::asio::ip::tcp;
class client
{
public:
client()
: socket_(io_service_),
deadline_(io_service_)
{
deadline_.expires_from_now(boost::posix_time::seconds(10));
check_deadline(); // without this line which means without the this timer
//async_wait, the code stuck in write_line io_service_.run_one() loop .
}
void connect_handler(const boost::system::error_code& error,boost::system::error_code *er)
{
std::cerr<<"connect handler"<<std::endl;
*er = error;
std::cerr<<error<<std::endl;
}
void connect(const std::string& host, const std::string& service)
{
tcp::resolver::query query(host, service);
tcp::resolver::iterator iter = tcp::resolver(io_service_).resolve(query);
std::cerr<<"connect start"<<std::endl;
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_connect(socket_, iter, bind(&client::connect_handler,this,_1,&ec));
do
{io_service_.run_one();
}while (ec == boost::asio::error::would_block);
std::cerr<<"connect done"<<std::endl; // always works fine!
if (ec || !socket_.is_open())
throw boost::system::system_error(
ec ? ec : boost::asio::error::operation_aborted);
}
void write_handler(const boost::system::error_code& error, std::size_t size,boost::system::error_code* er )
{
std::cerr<<"write handler "<<std::endl;
*er=error;
std::cerr<<error<<std::endl;
}
void write_line(const std::string& line)
{
std::cerr<<"write start"<<std::endl;
std::string data = line + "\n";
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_write(socket_, boost::asio::buffer(data), bind(&client::write_handler,this,_1,_2,&ec));
do
{
io_service_.run_one(); //stuck here without "check_deadline();" in constructor.
}while (ec == boost::asio::error::would_block);
std::cerr<<"write done";
if (ec)
throw boost::system::system_error(ec);
}
private:
void check_deadline()
{
if (deadline_.expires_at() <= deadline_timer::traits_type::now())
{
boost::system::error_code ignored_ec;
socket_.close(ignored_ec);
deadline_.expires_at(boost::posix_time::pos_infin);
throw boost::system::system_error(ignored_ec);
}
deadline_.async_wait(std::bind(&client::check_deadline, this));
}
boost::asio::io_service io_service_;
tcp::socket socket_;
deadline_timer deadline_;
};
int main()
{
try
{
client c,d;
c.connect("216.58.194.164", "80");// google IP.
c.write_line("test");
}
catch (std::exception& e)
{
std::cerr << "Exception: " << e.what() << "\n";
}
return 0;
}
Without comment out line "check_deadline();" in constructor the output is :
connect start
connect handler
system:0
connect done
write start
write handler
system:0
write done
when the line "check_deadline();" comment out in constructor, the output is :
connect start
connect handler
system:0
connect done
write start
and stuck there forever.
The whole point of that particular example is to have timeouts on blocking operations. This is why they use the async_* flavour of functions.
If you don't need that, don't use the async_* flavour at all:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
class client {
public:
client() : socket_(io_service_) { }
void connect(const std::string &host, const std::string &service) {
tcp::resolver::query query(host, service);
socket_.close();
boost::asio::connect(socket_, tcp::resolver(io_service_).resolve(query));
}
std::string read_line() {
boost::system::error_code ec;
boost::asio::read_until(socket_, input_buffer_, '\n', ec);
if (ec == boost::asio::error::eof)
socket_.close();
else if (ec)
throw boost::system::system_error(ec);
std::string line;
std::getline(std::istream(&input_buffer_), line);
return line;
}
void write_line(const std::string &line) {
std::string data = line + "\n";
boost::asio::write(socket_, boost::asio::buffer(data));
}
private:
boost::asio::io_service io_service_;
tcp::socket socket_;
boost::asio::streambuf input_buffer_;
};
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp <host> <port> <message>\n";
return 1;
}
client c;
c.connect(argv[1], argv[2]);
boost::posix_time::ptime time_sent = boost::posix_time::microsec_clock::universal_time();
c.write_line(argv[3]);
for (;;) {
std::string line = c.read_line();
std::cout << "Received '" << line << "'\n";
if (line == argv[3])
break;
}
boost::posix_time::ptime time_received = boost::posix_time::microsec_clock::universal_time();
std::cout << "Round trip time: ";
std::cout << (time_received - time_sent).total_microseconds();
std::cout << " microseconds\n";
} catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
That's a lot simpler. In fact, it's too simple in case the packets arriving contain more than 1 line at a time.
Instead of "fixing" the sample by re-complicating it, it can be ENORMOUSLY simpler:
#include <boost/asio.hpp>
#include <iostream>
#include <string>
using boost::asio::ip::tcp;
int main(int argc, char *argv[]) {
try {
if (argc != 4) {
std::cerr << "Usage: blocking_tcp <host> <port> <message>\n";
return 1;
}
tcp::iostream c(argv[1], argv[2]);
boost::posix_time::ptime time_sent = boost::posix_time::microsec_clock::universal_time();
c << argv[3] << "\n";
std::string line;
while (getline(c, line)) {
std::cout << "Received '" << line << "'\n";
if (line == argv[3])
break;
}
boost::posix_time::ptime time_received = boost::posix_time::microsec_clock::universal_time();
std::cout << "Round trip time: ";
std::cout << (time_received - time_sent).total_microseconds();
std::cout << " microseconds\n";
} catch (std::exception &e) {
std::cerr << "Exception: " << e.what() << "\n";
}
}
I have a boost::multiIndex container.
say :
typedef boost::multi_index<....
> OrderSet;
OrderSet orderSet_;
int main()
{
const auto it = orderSet_.get<0>().equal_range(boost::make_tuple(/* Some Values*/))
if(it.first != it.second)
while(it.second != it.first) { /* Somethings to do */;
--it.second;
}
}
the program crash with offset_ptr error.
for the program it has value on increasing order. so I want highest value first then so-on..
Is any a over-loaded function of boost::equal_range(..., [&](const auto a, const auto b)-> decltype bool{return a > b;});
Something like this. it's like reverse_iterator of equal_range()
UPDATE: multi-Index container is accessed by one producer and many consumer. while consumer is finding equal_range, producer add or delete elements and consumer throw the error... this is only happens when i am reverse iterating...
You're leaving out the essential part: the chosen index type.
Different index types afford different interfaces.
Then again, equal_range implies a ordered or unordered map. And because reversing the order on an unordered map is non-sense, I'm going to assume an ordered map.
Next, with make_tuple there I'm guessing composite keys.
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
struct X {
int i;
std::string name;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, std::string, &X::name>
>
>
>
> OrderSet;
Then here's the native order:
#include <iostream>
int main()
{
std::cout << std::unitbuf;
OrderSet orderSet_ {
{ 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
};
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// ...
And I'd use Boost Range to get the reverse order:
#include <boost/range/adaptor/reversed.hpp>
// ...
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
BONUS TAKE
Of course you can write the same manually:
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
--it.second;
auto& el = *it.second;
std::cout << el.i << "," << el.name << "; ";
}
Live Demo
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>
struct X {
int i; // = [] { static int gen = 0; return ++gen; }();
std::string name;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, std::string, &X::name>
>
>
>
> OrderSet;
#include <iostream>
int main()
{
std::cout << std::unitbuf;
OrderSet orderSet_ {
{ 1, "one" }, { 1, "two" }, { 2, "three" }, { 3, "four" }, { 2, "five" }
};
{
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
}
Prints
2,five; 2,three;
Now in reverse:
2,three; 2,five;
Also in reverse:
2,three; 2,five;
Even further out on a limb, since you said offset_ptr you might be using Boost Interprocess allocators.
Here's a demo that shows how you'd do the above correctly in a memory mapped/shared memory area:
Live On Coliru
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
namespace bmi = boost::multi_index;
namespace bip = boost::interprocess;
//namespace Shared { struct X; }
//namespace std { template<typename Alloc> struct uses_allocator<Shared::X, Alloc> : std::true_type {}; }
namespace Shared {
using Segment = bip::managed_mapped_file;
template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;
struct X {
using allocator_type = Alloc<char>;
template <typename Alloc>
X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}
int i;
String name;
};
typedef boost::multi_index_container<X,
bmi::indexed_by<
bmi::ordered_non_unique<
bmi::tag<struct by_i>,
bmi::composite_key<X,
bmi::member<X, int, &X::i>,
bmi::member<X, String, &X::name>
>
>
>,
Alloc<X>
> OrderSet;
}
#include <iostream>
int main()
{
std::cout << std::unitbuf;
Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);
auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());
if (orderSet_.empty()) {
// can't get multi-index to use the scoped allocator "magically" :(
orderSet_.emplace(1, "one", orderSet_.get_allocator());
orderSet_.emplace(1, "one", orderSet_.get_allocator());
orderSet_.emplace(1, "two", orderSet_.get_allocator());
orderSet_.emplace(2, "three", orderSet_.get_allocator());
orderSet_.emplace(3, "four", orderSet_.get_allocator());
orderSet_.emplace(2, "five", orderSet_.get_allocator());
}
{
auto const range = orderSet_/*.get<0>()*/.equal_range(boost::make_tuple(2));
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.get<0>().equal_range(boost::make_tuple(2));
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
std::cout << "\nBye\n";
}
Prints
2,five; 2,three;
Now in reverse:
2,three; 2,five;
Also in reverse:
2,three; 2,five;
Bye
Twice (proving all data was correctly in the shared memory segment).
BONUS TAKE
Apparently, Boost Multi-Index doesn't quite play completely well with the scoped allocator, because it would be more elegant with that:
Live On Coliru
#include <set>
#include <boost/interprocess/managed_mapped_file.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/string.hpp>
#include <boost/container/set.hpp>
#include <boost/container/scoped_allocator.hpp>
#include <boost/range/adaptor/reversed.hpp>
#include <boost/range/iterator_range.hpp>
namespace bip = boost::interprocess;
namespace Shared {
using Segment = bip::managed_mapped_file;
template <typename T> using Alloc = bip::allocator<T, Segment::segment_manager>;
using String = boost::interprocess::basic_string<char, std::char_traits<char>, Alloc<char> >;
struct X {
using allocator_type = Alloc<char>;
template <typename Alloc>
X(int i, std::string const& s, Alloc alloc) : i(i), name(s.begin(), s.end(), alloc) {}
bool operator<(X const& other) const { return i < other.i; }
bool operator<(int other) const { return i < other; }
int i;
String name;
};
template <typename T>
using Multiset = boost::container::multiset<
T,
std::less<T>,
boost::container::scoped_allocator_adaptor<Alloc<X> >
>;
using OrderSet = Multiset<X>;
}
#include <iostream>
int main()
{
std::cout << std::unitbuf;
Shared::Segment mmf(bip::open_or_create, "test.data", 10u << 10);
auto& orderSet_ = *mmf.find_or_construct<Shared::OrderSet>("set")(mmf.get_segment_manager());
if (orderSet_.empty()) {
// scoped-allocator automatically propagates to the string
orderSet_.emplace(1, "one");
orderSet_.emplace(1, "one");
orderSet_.emplace(1, "two");
orderSet_.emplace(2, "three");
orderSet_.emplace(3, "four");
orderSet_.emplace(2, "five");
}
{
auto const range = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
for (auto& el : boost::make_iterator_range(range))
std::cout << el.i << "," << el.name << "; ";
// traverse these in reverse
std::cout << "\nNow in reverse:\n";
for (auto& el : range | boost::adaptors::reversed)
std::cout << el.i << "," << el.name << "; ";
}
{
std::cout << "\nAlso in reverse:\n";
auto it = orderSet_.equal_range({2, "", orderSet_.get_allocator()});
while(it.second != it.first) {
auto& el = *(--it.second);
std::cout << el.i << "," << el.name << "; ";
}
}
std::cout << "\nBye\n";
}
I am trying to go threw a vector of Student objects. If I find a matching ID to the one I am searching for it will display their info.
However, when I try to find a specific ID .compare isn't seeing a match even though it should.
My output: first line is the ID I am looking for, second is the current ID being looked at, then is the result of the compare.
a11111111
a22222222
-1
no match
a11111111
a11111111
-1
no match
Asked for more of the code so here is the entire program: (issue in displayID)
header file
#ifndef structures_h
#define structures_h
#include <vector>
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <fstream>
#include <sstream>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <map>
using namespace std;
main program
#endif
typedef pair<string, string> Name; // first name, last name
typedef map<string, int> Grades; // map courses to scores
#include "struct.h"
class Student {
public:
void display(ostream& os) const;
void setId(string);
void setName(string, string);
void setGrades(string, int);
string getId();
string getName();
void getGrades();
bool operator<(const Student &rhs) const { return id_ < rhs.id_; }
private:
string id_; // e.g. "a22222222"
Name name_; // e.g. {"ned", "flanders"}
Grades grades_;
};
void Student::setId(string id) {
id_ = id;
}
string Student::getId() {
return id_;
}
void Student::setName(string first, string last) {
name_ = pair<string,string>(first, last);
}
string Student::getName() {
return get<0>(name_) + ' ' + get<1>(name_);
}
void Student::setGrades(string course, int score) {
grades_.insert(make_pair(course, score));
}
void Student::getGrades() {
for(auto it = grades_.begin(); it != grades_.end(); ++it) {
cout << it -> first << ' ' << it -> second << endl;
}
}
vector<Student> addStudent(int count, int x, vector<Student>& vStu, string file) {
string line, first, last;
ifstream infile(file);
while (getline(infile, line)) {
vStu.push_back(Student());
vStu[count].setId(line);
getline(infile, line);
istringstream iss(line);
if (!(iss >> first >> last)) {
cout << "failed to get name" << endl;
break;
}
vStu[count].setName(first, last);
getline(infile, line);
istringstream iss2(line);
if (!(iss2 >> x)) {
cout << "failed to get class number" << endl;
break;
}
for (int i = 0; i < x; i++) {
string sClass;
int grade;
getline(infile, line);
istringstream iss3(line);
if (!(iss3 >> sClass >> grade)) {
cout << "failed to get class and grade" << endl;
break;
}
vStu[count].setGrades(sClass, grade);
}
count++;
}
return vStu;
}
void display(vector<Student>& vStu) {
sort(vStu.begin(), vStu.end());
cout << endl;
int count = vStu.size();
for (int i = 0; i<count;i++) {
cout << vStu[i].getId() << endl;
cout << vStu[i].getName() << endl;
vStu[i].getGrades();
cout << endl;
}
}
void displayID(vector<Student>& vStu, string ID) {
int count = vStu.size();
string test;
ID = "a11111111";
for (int i = 0; i<count;i++) {
cout<< endl;
test = vStu[i].getId();
cout << ID << endl;
cout << test << endl;
cout << ID.compare(test) << endl;
if (ID.compare(test) == 0) {
cout << "match" << endl;
cout << vStu[i].getId() << endl;
cout << vStu[i].getName() << endl;
vStu[i].getGrades();
cout << endl;
} else {
cout << "no match" << endl;
}
}
cout << endl;
}
void mainMenu(vector<Student>& vStu) {
string input;
string word;
vector<string> com;
while(1) {
cout << "Enter command: ";
getline(cin,input);
istringstream iss(input);
while(iss >> word) {
com.push_back(word);
}
for (int i = 0; i < (int)com.size(); i++) {
transform(com[i].begin(), com[i].end(), com[i].begin(), ::tolower);
if (com[i] == "show") {
display(vStu);
} else if (com[i] == "showid") {
displayID(vStu, "a11111111");
}
}
com.clear();
}
}
int main(int argc, char *argv[]) {
vector<Student> vStu;
int count = 0, x = 0;
if (argc != 2) {
cout << "Incorrectly called" << endl;
cout << " " << argv[0] << ' ' << "<filename>" << endl;
return 1;
}
addStudent(count, x, vStu, argv[1]);
mainMenu(vStu);
}
The only possibility I see is that there is some whitespace at the end of the string that gets passed into your function. Try trimming the end of the string's like this this thread suggests before comparing and see if they still don't compare correctly.
I have Created a Print Class where I have created all of those functions.
When I attempt to call these functions, I get the Identifier Error. I am sure I have incorrectly set up my class. Please Help construct Print Class
Code attached:
// Print.cpp - Print Class implementation
// Written by Varun Patel
#include "Print.h"
Print::Print()
{
}
Print::Print(const string& word)
{
Word = word;
}
void Print::PrintWordsRemaining(set<string>& possibleWords_, bool displayNumberOfWordsRemaining_)
{
if(displayNumberOfWordsRemaining_)
{
cout << "There are " << possibleWords_.size() << " possible words left." << endl;
}
else
{
//Do nothing
}
}
void Print::PrintWordSpaceDelinated(string word_)
{
for (size_t i = 0; i < word_.size(); i++)
{
cout << word_[i] << " ";
}
cout << endl;
}
void Print::PrintGuessesRemaining(int guessesRemaining_)
{
cout << "You have " << guessesRemaining_ << " guesses remaining." << endl;
}
Here is how i try to call one of the functions:
#include "UpdateGuessesRemaining.h"
void UpdateGuessesRemaining(set<string>& newPossibleWords, int& guessesRemaining,
char guessChar, string& guessedWord)
{
set<string>::iterator wordPtr = newPossibleWords.begin();
if (wordPtr->find(guessChar) == -1)
{
cout << "Sorry, incorrect guess. ";
PrintGuessesRemaining(--guessesRemaining);
}
else
{
cout << "Correct! The word contains " << guessChar << "." << endl;
}
}
Here is my header File:
// Print.h - Print Class declaration
// Written by Varun Patel
#pragma once
#include <iostream>
#include <set>
#include <string>
#include "PromptForGuessesRemaining.h"
using namespace std;
class Print
{
public:
// Default constructor
Print();
Print(const string& word);
void PrintWordsRemaining(set<string>& possibleWords, bool displayNumberOfWordsRemaining);
void PrintWordSpaceDelinated(string word);
void PrintGuessesRemaining(int guessesRemaining);
private:
string Word;
};
Thanks For Your Help,
Varun