How to PAUSE and PLAY stream with Live555 - rtsp

I'm accessing a video server with Live555 that is streaming to another program. I want to send rtsp PAUSE and PLAY commands to the video server to stop streaming to any other program. Is this possible? My code does not seem to do anything. I can connect to the server and the server verifies that I have received a full PAUSE command:
VideoServer.h
//must make this store session so we can access the session in the static
//callbacks
class MyRTSPClient: public RTSPClient{
protected:
MyRTSPClient(UsageEnvironment& env, char const* rtspURL,
int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum):
RTSPClient(env, rtspURL, verbosityLevel, applicationName, tunnelOverHTTPPortNum)
{
}
public:
MediaSession* session_;
bool sessionStarted_;
static MyRTSPClient* createNew(UsageEnvironment& env, char const* rtspURL,
int verbosityLevel = 0,
char const* applicationName = NULL,
portNumBits tunnelOverHTTPPortNum = 0)
{
return new MyRTSPClient(env, rtspURL, verbosityLevel, applicationName, tunnelOverHTTPPortNum);
}
};
class VideoServer
{
public:
VideoServer();
private:
TaskScheduler* scheduler_;
UsageEnvironment* env_;
MyRTSPClient* rtspClient_;
char eventLoopWatchVariable;
//Asynchronously start the connection
void StartConnection();
static void callbackDESCRIBE(RTSPClient* rtspClient, int resultCode, char* resultString);
static void callbackPAUSEPLAY(RTSPClient* rtspClient, int resultCode, char* resultString);
};
VideoServer.cpp
VideoServer::VideoServer()
{
eventLoopWatchVariable = 0;
scheduler_ = BasicTaskScheduler::createNew();
env_ = BasicUsageEnvironment::createNew(*scheduler_);
//create rtsp client with default params and our url and environment
rtspClient_ = MyRTSPClient::createNew(*env_,
MINI_HARV_AXIS_RTSP_URL, 4, "jtalon5");
//call description to initialize the session
if (rtspClient_ == NULL) {
std::cout << "Failed to create a RTSP client for URL \"" <<
MINI_HARV_AXIS_RTSP_URL << std::endl;
return;
}
std::cout << "made the client!" << std::endl;
// Next, send a RTSP "DESCRIBE" command, to get a SDP description for the stream.
// Note that this command - like all RTSP commands - is sent asynchronously; we do not block, waiting for a response.
// Instead, the following function call returns immediately, and we handle the RTSP response later, from within the event loop:
rtspClient_->sendDescribeCommand(callbackDESCRIBE);
//start doEventLoop in separate thread so it is not blocking
boost::thread thr1(&MiniHarvAxisInterface::StartConnection, this);
}
void VideoServer::StartConnection()
{
env_->taskScheduler().doEventLoop(&eventLoopWatchVariable);
}
void MiniHarvAxisInterface::callbackDESCRIBE(RTSPClient* rtspClient, int resultCode, char* resultString)
{
std::cout << "describe" << resultString << std::endl;
UsageEnvironment& env = rtspClient->envir();
char* const sdpDescription = resultString;
((MyRTSPClient*)rtspClient)->session_ = MediaSession::createNew(env, sdpDescription);
((MyRTSPClient*)rtspClient)->sessionStarted_ = true;
if(((MyRTSPClient*)rtspClient)->session_ == NULL)
std::cout << "did not create session" << std::endl;
else
std::cout << "created session" << std::endl;
rtspClient->sendPauseCommand(*((MyRTSPClient*)rtspClient)->session_, &callbackPAUSEPLAY);
}
void MiniHarvAxisInterface::callbackPAUSEPLAY(RTSPClient* rtspClient, int resultCode, char* resultString)
{
//do nothing
}
It seems as if I can only pause and play a stream that I create in this process. Is this the case using Live555?

Yes this is possible in Live555.
By default Live555 does nothing unless you redefine the pauseStream function (see comment in pauseStream function in Live555 source below):
// default implementation: do nothing
You must create your own session class and you must redefine the pauseStream function as shown in the example below:
Your media session .h file should look something like:
#include <MediaSubsession.hh>
class YOURMediaSubsession: public MediaSubsession {
... //You can leave this empty if you like
private:
...
virtual void pauseStream(unsigned /*clientSessionId*/,void* /*streamToken*/);
};
Your media session .cpp file should look something like:
#include <YOURMediaSubsession.hh>
void YOURMediaSubsession::pauseStream(unsigned /*clientSessionId*/,
void* /*streamToken*/) {
// default implementation: do nothing
}
The you can add whatever you like in this function, whether it may be stopping/terminating all streams, or getting the encoder to keep encoding and the same frame to give the illusion of having the stream paused for a pre-set amount of time is all up to you.
Note that I can see in your code that you are using a default MediaSession class as shown in your code here:
((MyRTSPClient*)rtspClient)->session_ = MediaSession::createNew(env, sdpDescription);
You will need to construct your own YOURMediaSubsession class based on the MediaSession class to redefine the pauseStream function as shown above then YOU do the pausing, not live555. It should look more like:
((MyRTSPClient*)rtspClient)->session_ = YOURMediaSubsession::createNew(env, sdpDescription);

Related

use a lambda to start a thread which is a class attribute

I would like to assign a name to a thread, the thread itself must do this. The thread is a class member of the class foo.
I would like to start this thread with a lambda but unfortunately I get the error message:
no match for call to '(std::thread) (foo::start()::<lambda()>)
Can someone explain to me where the problem is?
Previously I had created a temporary thread object, and put this with move on the thread "manage", however, I can then give no name.
class foo {
public:
int start()
{
this->manage([this](){
auto nto_errno = pthread_setname_np(manage.native_handle(),"manage"); // Give thread an human readable name (non portable!)
while(1){
printf("do work");
}
});
return 1;
}
private:
int retVal;
std::thread manage;
};
You passed the lambda in a wrong way, after initialization the manage thread can't be initialized again. you should create a new std::thread and assign it.
the following compiles and indeed prints "manage".
class foo {
public:
int start()
{
manage = std::thread([this]{
auto nto_errno = pthread_setname_np(manage.native_handle(),"manage");
char name[16];
pthread_getname_np(pthread_self(), &name[0], sizeof(name));
cout << name << endl;
});
manage.join();
return 1;
}
private:
int retVal;
std::thread manage;
};

cannot handle QNetworkAccessManager::finised signal in multithreading

I want to serialize network requests using QNetworkAccessManager. For achieving it i wrote such class:
#ifndef CLIENT_H
#define CLIENT_H
#include <queue>
#include <mutex>
#include <condition_variable>
#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>
#include <QtNetwork/QNetworkRequest>
class Client : public QObject
{
Q_OBJECT
struct RequestRecord
{
RequestRecord(QString u, int o):url(u),operation(o){}
QString url;
int operation;
};
std::mutex mutex;
std::queue<RequestRecord*> requests;
QNetworkAccessManager *manager;
bool running;
std::condition_variable cv;
public:
Client():manager(nullptr){}
~Client()
{
if(manager)
delete manager;
}
void request_cppreference()
{
std::unique_lock<std::mutex> lock(mutex);
requests.push(new RequestRecord("http://en.cppreference.com",0));
cv.notify_one();
}
void request_qt()
{
std::unique_lock<std::mutex> lock(mutex);
requests.push(new RequestRecord("http://doc.qt.io/qt-5/qnetworkaccessmanager.html",1));
cv.notify_one();
}
void process()
{
manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
{
std::unique_lock<std::mutex> lock(mutex);
RequestRecord *front = requests.front();
requests.pop();
delete front;
reply->deleteLater();
});
running = true;
while (running)
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
RequestRecord *front = requests.front();
manager->get(QNetworkRequest(QUrl(front->url)));
}
}
};
#endif // CLIENT_H
As one can see, there are 2 methods for requesting data from network and method process, which should be called in separate thread.
I'm using this class as follows:
Client *client = new Client;
std::thread thr([client](){
client->process();
});
std::this_thread::sleep_for(std::chrono::seconds(1));
client->request_qt();
std::this_thread::sleep_for(std::chrono::milliseconds(1));
client->request_cppreference();
This example illustrate 2 consecutive requests to network from one thread and processing of these request in another. All works fine except my lambda is never called. Requests are sent (checked it using wireshark), but i cannot get replies. What is the cause?
as #thuga suppose the problem was in event loop. My thread always waiting on cv and thus cannot process events, little hack solve the problem:
void process()
{
manager = new QNetworkAccessManager;
connect(manager,&QNetworkAccessManager::finished,[this](QNetworkReply *reply)
{
std::unique_lock<std::mutex> lock(mutex);
RequestRecord *front = requests.front();
requests.pop();
delete front;
qDebug() << reply->readAll();
processed = true;
reply->deleteLater();
});
running = true;
while (running)
{
{
std::unique_lock<std::mutex> lock(mutex);
cv.wait(lock);
if(requests.size() > 0 && processed)
{
RequestRecord *front = requests.front();
manager->get(QNetworkRequest(QUrl(front->url)));
processed = false;
QtConcurrent::run([this]()
{
while (running)
{
cv.notify_one();
msleep(10);
}
});
}
}
QCoreApplication::processEvents();
}
}
};
it's not beautiful obvious since it is using 3 threads instead of 2, but it is Qt with this perfect phrase:
QUrl QNetworkReply::url() const Returns the URL of the content
downloaded or uploaded. Note that the URL may be different from that
of the original request. If the
QNetworkRequest::FollowRedirectsAttribute was set in the request, then
this function returns the current url that the network API is
accessing, i.e the url emitted in the QNetworkReply::redirected
signal.

Can't exit exec loop in Qt

Well, I have created a program which picks up the input signal from serial input. I can successfully receive the data transmitted from the device through UART. I want to terminate the thread after achieving certain conditions( such as receiving more than 5 bytes, etc.) I think the problem is how to terminate the thread in Qt correctly, but I couldn't find the way. The program seems falls into deadlock after calling the exec() in the sub function. Can anyone help with that problem? Thank you very much!
Here's my header file:
#ifndef SERIALTHREAD
#define SERIALTHREAD
#include <QtSerialPort/QSerialPort>
#include <QDebug>
#include <QString>
#include <QThread>
#include <QtCore>
#include <iostream>
#include <fstream>
class SerialControlThread : public QThread
{
Q_OBJECT
public:
explicit SerialControlThread(QString ComPort,QObject *parent = 0);
~SerialControlThread(); // Destructor
bool openSerialPort();
void closeSerialPort();
void run();
bool TelltoExit();
void StarttoRun();
private:
int DataCount;
QString ComPortNumber;
QSerialPort *serial;
int* VoltageStorage; // Total 3 channels, each channel takes 10 data
unsigned int Channel_A[10]; // Channel_A is for Phase Tx s
int DataCountIndexA; // This is how many data has been sent to the buffer;
int SentDataCount;
unsigned char StoreDataBuffer[2];
unsigned char TotalDataCounter;
std::ofstream write;
signals:
void BufferisFull(int*);
void TimeToQuit();
public slots:
private slots:
void readData();
void handleError(QSerialPort::SerialPortError error);
};
#endif // SERIALTHREAD
This is the.cpp
#include "serialcontrol.h"
#include <iostream>
SerialControlThread::SerialControlThread(QString ComPort,QObject *parent) :
QThread(parent),ComPortNumber(ComPort)
{
DataCountIndexA=0;
DataCount=0;
serial = new QSerialPort(this);
connect(this,SIGNAL(TimeToQuit()),this,SLOT(quit()));\
connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this,
SLOT(handleError(QSerialPort::SerialPortError)));
for (int i=0;i<10;i++)
Channel_A[i]=0;
}
SerialControlThread::~SerialControlThread()
{
this->closeSerialPort();
delete serial;
}
bool SerialControlThread::openSerialPort()
{
// std::cout << "Hey I am in serial function" << std::endl;
serial->setPortName(ComPortNumber) ;
serial->setBaudRate(QSerialPort::Baud9600); //This can be set through menu in the future
serial->setDataBits(QSerialPort::Data8); // A packets contains 8 bits ( 3 for signature bits)
serial->setParity(QSerialPort::NoParity);
serial->setStopBits(QSerialPort::OneStop);
serial->setFlowControl(QSerialPort::NoFlowControl);
if (!(serial->open(QIODevice::ReadWrite))) {
return false; // return false when the device can't be opened
}else
{
return true;} // return true when the device is avalaible
}
void SerialControlThread::closeSerialPort()
{
if (serial->isOpen())
serial->close();
}
void SerialControlThread::handleError(QSerialPort::SerialPortError error)
{
}
void SerialControlThread::readData()
{
QByteArray data=serial->read(100);
const char *TempChar=data.data();
std::cout << TempChar << std::endl;
DataCount++;
if(DataCount>=4)
{
std::cout << "I am bigger than 4" << std::endl;
this->quit();
}
}
}
void SerialControlThread::run()
{
}
bool SerialControlThread::TelltoExit()
{
}
void SerialControlThread::StarttoRun()
{
// Sending the msp430 S to activate the following sequence
const char *temp="S";
serial->write(temp);
serial->waitForBytesWritten(30000);
this->exec();
}
This is the main.cpp
#include <QCoreApplication>
#include <QtSerialPort/QSerialPortInfo>
#include <QList>
#include <iostream>
#include <QString>
#include <QDebug>
#include <QSerialPort>
#include "serialcontrol.h"
using namespace std;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int AvailablePorts=QSerialPortInfo::availablePorts().count();
QList<QSerialPortInfo> SerialObject=QSerialPortInfo::availablePorts();
cout << "There are total: " << SerialObject.count() << " available ports " << endl << endl;
QString description;
for (int i=0;i<AvailablePorts;i++)
{
cout << "The " << i+1 << " com port is :";
qDebug() << SerialObject[i].portName();
qDebug() << "Description : " << SerialObject[i].description();
qDebug() << "Manufacturer: " << SerialObject[i].manufacturer();
cout << endl;
}
SerialControlThread *RunThread=new SerialControlThread(SerialObject[0].portName(),&a);
cout << RunThread->openSerialPort() << endl;
RunThread->StarttoRun();
cout << "I am out of here" << endl;
delete RunThread;
return a.exec();
}
I wish to close the thread( back to the main function) when the buffer has received more than 4 data, but it doesn't.
It is my output
There are total: 1 available ports
The 1 com port is :"COM8"
Description : "MSP430 Application UART"
Manufacturer: "Texas Instruments"
1
0
1
2
3
I am bigger than 4
4
I am bigger than 4
5
I am bigger than 4
6
I am bigger than 4
7
I am bigger than 4
8
I am bigger than 4
9
I am bigger than 4
Apparently, the program gets stuck in a loop. I have tried some solutions, but none of these worked.
StartToRun calls QThread::exec in the wrong thread: you call it in the main thread, but it's supposed to be called in the thread itself - from within run().
Alas, SerialControlThread doesn't have to be a thread. Making it a thread forces it to be used in a dedicated thread - that should be a choice left to its user. Perhaps the thread would be shared among other serial controllers, or perhaps it'll do just fine in the main thread. Thus, it should be an object that handles serial data, that has a thread-safe interface so that you can move it to another thread if you wish - but would still work fine in the main thread, and thus has to handle data asynchronously without blocking.
Considering whether one needs to control the worker thread's run status so tightly: an idle thread consumes no resources - its event loop is blocked waiting on new events, its stack eventually gets paged out if there's memory pressure. If one intends to "wake" the thread for each operation, there's no need to be explicit about it: the event loop in the thread behaves that way be default and by design: it wakes when there are new events, such as incoming data, otherwise it sleeps. One shouldn't be stopping the thread then.
The example below shows a very minimal implementation. On the whole it's not very useful other than to demonstrate brevity as a contrast to the length of code in the question - in spite of identical limited functionality. Presumably you have a more complex communications protocol that you wish to handle. You may wish to consider the use of QDataStream read transactions to make the reader code more expressive, and using a state machine to represent the protocol.
// https://github.com/KubaO/stackoverflown/tree/master/questions/serial-galore-42241570
#include <QtWidgets>
#include <QtSerialPort>
// See https://stackoverflow.com/q/40382820/1329652
template <typename Fun> void safe(QObject * obj, Fun && fun) {
Q_ASSERT(obj->thread() || qApp && qApp->thread() == QThread::currentThread());
if (Q_LIKELY(obj->thread() == QThread::currentThread() || !obj->thread()))
return fun();
struct Event : public QEvent {
using F = typename std::decay<Fun>::type;
F fun;
Event(F && fun) : QEvent(QEvent::None), fun(std::move(fun)) {}
Event(const F & fun) : QEvent(QEvent::None), fun(fun) {}
~Event() { fun(); }
};
QCoreApplication::postEvent(
obj->thread() ? obj : qApp, new Event(std::forward<Fun>(fun)));
}
class SerialController : public QObject {
Q_OBJECT
QSerialPort m_port{this};
QByteArray m_rxData;
void onError(QSerialPort::SerialPortError error) {
Q_UNUSED(error);
}
void onData(const QByteArray & data) {
m_rxData.append(data);
qDebug() << "Got" << m_rxData.toHex() << "(" << m_rxData.size() << ") - done.";
emit hasReply(m_rxData);
}
void onData() {
if (m_port.bytesAvailable() >= 4)
onData(m_port.readAll());
}
public:
explicit SerialController(const QString & port, QObject * parent = nullptr) :
QObject{parent}
{
m_port.setPortName(port);
connect(&m_port, static_cast<void(QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error),
this, &SerialController::onError);
}
~SerialController() { qDebug() << __FUNCTION__; }
bool open() {
m_port.setBaudRate(QSerialPort::Baud9600);
m_port.setDataBits(QSerialPort::Data8);
m_port.setParity(QSerialPort::NoParity);
m_port.setStopBits(QSerialPort::OneStop);
m_port.setFlowControl(QSerialPort::NoFlowControl);
return m_port.open(QIODevice::ReadWrite);
}
/// This method is thread-safe.
void start() {
safe(this, [=]{
m_port.write("S");
qDebug() << "Sent data";
});
}
Q_SIGNAL void hasReply(const QByteArray &);
void injectData(const QByteArray & data) {
onData(data);
}
};
QDebug operator<<(QDebug dbg, const QSerialPortInfo & info) {
dbg << info.portName();
if (!info.description().isEmpty())
dbg << " Description: " << info.description();
if (!info.manufacturer().isEmpty())
dbg << " Manufacturer: " << info.manufacturer();
return dbg;
}
// A thread that starts on construction, and is always safe to destruct.
class RunningThread : public QThread {
Q_OBJECT
using QThread::run; // final
public:
RunningThread(QObject * parent = nullptr) : QThread(parent) { start(); }
~RunningThread() { qDebug() << __FUNCTION__; quit(); wait(); }
};
int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
auto const ports = QSerialPortInfo::availablePorts();
if (ports.isEmpty())
qFatal("No serial ports");
int n{};
qDebug() << "Available ports:";
for (auto & port : ports)
qDebug() << "port[" << n++ << "]: " << port;
SerialController ctl{ports.at(5).portName()};
if (!ctl.open())
qFatal("Open Failed");
// Optional: the controller will work fine in the main thread.
if (true) ctl.moveToThread(new RunningThread{&ctl}); // Owns its thread
// Let's pretend we got a reply;
QTimer::singleShot(1000, &ctl, [&ctl]{
ctl.injectData("ABCD");
});
QObject::connect(&ctl, &SerialController::hasReply, ctl.thread(), &QThread::quit);
QObject::connect(&ctl, &SerialController::hasReply, [&]{
qDebug() << "The controller is done, quitting.";
app.quit();
});
ctl.start();
return app.exec();
}
#include "main.moc"

QNetworkAccessManager get called in a QThread because cyclic

I need to call a web request cyclically, so, the easy way to do that is, of course, create a thread and call my request followed by a sleep..
The issue is that I wrote my code and it basically works. When I try to call the get inside a QThread, I don't receive any result, the event associated to the response is never invoked:
class RemoteControl : public QObject {
Q_OBJECT
QNetworkAccessManager* manager;
public:
explicit RemoteControl(QObject* parent = 0);
~RemoteControl() {}
public slots:
void process() {
std::cout << "start" << std::endl;
while (true) {
execute();
std::cout << "called" << std::endl;
sleep(5);
}
}
void execute() {
QUrl url("my request for num of visitors that works..");
QNetworkRequest req;
req.setUrl(url);
req.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/x-www-form-urlencoded"));
QNetworkReply* reply = manager->get(req);
}
void downloadFinished(QNetworkReply* reply) {
std::cout << "finished called" << std::endl;
QByteArray resp = reply->readAll();
std::cout << resp.data() << std::endl;
}
signals:
void finished();
private:
WebRequest* WebReq_;
};
RemoteControl::RemoteControl(bool* enable, LoggerHandle* Log, QObject* parent) : QObject(parent)
{
enable_ = enable;
Log_ = Log;
running_ = false;
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply*)), this,
SLOT(downloadFinished(QNetworkReply*)));
}
int main() {
//.... my code....
QThread* t3 = new QThread;
RemoteContr->moveToThread(t3);
QObject::connect(t3, SIGNAL(started()), RemoteContr, SLOT(process()));
t3->start();
//.... my code....
}
So, what happens is that using this code I didn't get any errors, in the output I can see start and called but never finished called..
it seems that the event downloadFinished is never called.
Can you help me to understand why?
Something wrong in my class RemoteControl?
Thanks
Andrea
You don't need a thread for this. The QNetworkAccessManager is asynchronous, so the calls you're using do not block. Instead of a thread, just do something like this in your main function:
QTimer * timer = new QTimer;
connect(timer, SIGNAL(timeout()), RemoteContr, SLOT(execute());
timer->start(5000); // = 5 seconds
Then, execute is invoked every 5 seconds, which seems to be what you want.
By the way, I think the reason you aren't getting results is that the while loop in process is blocking the thread. You can get rid of the process slot with this approach.

boost library multithread socket strangeness

I've been stuck for a whole night but can't figure out the problem.
I'm writing a server that accepts connections for a chatroom application. The idea is that the server gives the connected sockets to chat_manager, chat_manager puts them in a waitlist and starts a thread to constantly check if somebody is still in the waitlist. If somebody is in the waitlist, the chat_manager tries to read from the client to determine which room the client wants to join.
main.cpp looks like this :
boost::asio::io_service io_service;
chat_server server(io_service, 8091);
io_service.run();
Chat server code :
chat_server::chat_server(boost::asio::io_service& io_service, int port) : io_service_(io_service),
acceptor_(io_service, tcp::endpoint(tcp::v4(), port)) {
start_accept();
}
void chat_server::start_accept() {
chat_session_ptr new_session(new chat_session(io_service_));
acceptor_.async_accept(new_session->socket(), boost::bind(&chat_server::handle_accept, this, new_session,
boost::asio::placeholders::error));
}
void chat_server::handle_accept(chat_session_ptr s, const boost::system::error_code& error) {
if (!error) { // successfully connected
chat_manager::Instance().chat_session_join(s);
}
start_accept();
}
chat_manager is simply
chat_manager() { // constructor
waitlist_.resize(0);
manager_thread_ = boost::thread(&chat_manager::run, this);
}
int chat_session_join(chat_session_ptr chat_session) {
mutex_.lock();
waitlist_.push_back(chat_session);
mutex_.unlock();
return 1;
}
void run() {
while (1) {
mutex_.lock();
for (auto &s : waitlist_) {
std::string roomname;
if (s->wait_for_join(roomname)) {
...
}
break;
}
mutex_.unlock();
boost::this_thread::sleep( boost::posix_time::milliseconds(10) );
}
}
And session.cpp :
jsoncons::json chat_session::receive_request(boost::system::error_code& error) {
buffer_.consume(buffer_.size());
size_t bytes_transferred;
boost::system::error_code ec = boost::asio::error::would_block;
boost::asio::async_read_until(socket_, buffer_, "\n",
boost::bind(&chat_session::handle_read, shared_from_this(), _1, _2, &ec, &bytes_transferred ));
deadline_.expires_from_now(boost::posix_time::seconds(2));
deadline_.async_wait(boost::bind(&chat_session::check_deadline, shared_from_this()));
do pio_service_->run_one(); while (ec == boost::asio::error::would_block);
std::cout << "got it" << std::endl;
if ( ec || !socket_.is_open() ) {
std::cout << ec.message() << std::endl;
return jsoncons::json();
}
std::istream is(&buffer_);
return jsoncons::json::parse(is);
}
int chat_session::wait_for_join(std::string &roomname) {
boost::system::error_code error;
jsoncons::json request = receive_request(error);
...
}
void chat_session::handle_read(const boost::system::error_code& error, size_t bytes_transferred,
boost::system::error_code* out_error, size_t* out_bytes_transferred) {
deadline_.expires_at(boost::posix_time::pos_infin);
*out_error = error;
*out_bytes_transferred = bytes_transferred;
if (!error) {
} else {
std::cout << "handle_read error:" << error.message() << std::endl;
}
}
What happens is,
1. when the client connects and doesn't send anything, the connection is closed by the server after 2 seconds. which is correct. but
2. if the client sends one string before the connection expires, the server worked its way into handle_read but never gets past pio_service->run_one();
3. if the client send another string, wait_for_join will finish and the run() procedure starts to loop.
To me it seems that the use of io_services here is fine because check_deadline and handle_read worked, but if that really worked it would modify ec != would_block, and the do-while loop should return. What's happening here? I'm really confused.

Resources