Qt_26 - 8BitsCoding/RobotMentor GitHub Wiki
์ฐธ๊ณ ๋ก ์๋ก์ด QObject๋ฅผ ์ถ๊ฐํ๊ธฐ ์ํด์๋
project์ run qmake๋ฅผ ์๋ก ๋น๋ํด์ค์ผํ๋ค.

#include "asioclient.h"
#include <qdebug.h>
AsioClient::AsioClient() :
work(new boost::asio::io_service::work(ioservice)),
resolver(ioservice),
socket(ioservice)
{
worker = std::thread([&](){
ioservice.run();
});
}
AsioClient::~AsioClient(){
ioservice.stop();
worker.join();
work.reset();
}
void AsioClient::Get(const QString& url, const QString& p)
{
// 1. url -> ep resolve
server = url.toStdString();
path = p.toStdString();
boost::asio::ip::tcp::resolver::query query(server, "http");
resolver.async_resolve(query, boost::bind(&AsioClient::handle_resolve,
this,
boost::asio::placeholders::error,
boost::asio::placeholders::iterator));
// 2. connect
// 3. send
// 4. recv
}
void AsioClient::handle_resolve(const boost::system::error_code& err, boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if(!err) {
boost::asio::ip::tcp::endpoint ep = *endpoint_iterator;
qDebug() << ep.address().to_string().c_str();
socket.async_connect(*endpoint_iterator,
boost::bind(&AsioClient::handle_connect,
this,
boost::asio::placeholders::error,
endpoint_iterator));
}
}
void AsioClient::handle_connect(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator)
{
if(!err) {
// success
// write
std::ostream os(&requestbuf);
os << "GET" << path << " HTTP/1.0\r\n";
os << "Host: " << server << "\r\n";
os << "Accept: */*\r\n";
os << "Connection: close\r\n\r\n";
boost::asio::async_write(socket, requestbuf,
boost::bind(&AsioClient::handle_write,
this,
boost::asio::placeholders::error));
} else {
qDebug() << err.message().c_str() << endl;
}
}
void AsioClient::handle_write(const boost::system::error_code& err)
{
// recv
if(!err) {
boost::asio::async_read_until(socket, responsebuf, "\r\n",
boost::bind(&AsioClient::handle_read_line,
this,
boost::asio::placeholders::error));
} else {
qDebug() << "handle_Write error : " << err.message().c_str() << endl;
}
}
void AsioClient::handle_read_line(const boost::system::error_code& err)
{
if(!err) {
std::istream is(&responsebuf);
std::string http_version;
unsigned int status_code;
std::string message;
is >> http_version;
is >> status_code;
std::getline(is, message);
// Error Check
// 1. http_version HTTP/
// 2. status_code != 200
if(status_code != 200) {
return ;
}
// ๊ฐํ๋ฌธ์(\r\n\r\n) ๋๋ฒ ๋์ค๋ ๋ถ๋ถ๋ถํฐ ๋ฉ์์ง์ ๋ณธ๋ฌธ์ด๋ค.
// ๊ทธ ์ด์ ๋ฉ์์ง๋ ๋ชจ๋ ํค๋์ด๋ค.
boost::asio::async_read_until(socket, responsebuf, "\r\n\r\n",
boost::bind(&AsioClient::handle_read_header,
this,
boost::asio::placeholders::error));
} else {
}
}
void AsioClient::handle_read_header(const boost::system::error_code& err)
{
std::istream istrm(&responsebuf);
std::string header;
while(std::getline(istrm, header) && header != "\r") {
// header
//oss << header << std::endl;
// ๋ณธ๋ฌธ ๋ด์ฉ๋ง ๋ฐ๋๋ค.
}
boost::asio::streambuf::const_buffers_type bufs = responsebuf.data();
std::string str(boost::asio::buffers_begin(bufs),
boost::asio::buffers_begin(bufs) + responsebuf.size());
oss << str ;
boost::asio::async_read(socket, responsebuf,
boost::asio::transfer_at_least(1),
boost::bind(&AsioClient::handle_read_content,
this,
boost::asio::placeholders::error));
}
void AsioClient::handle_read_content(const boost::system::error_code& err)
{
if(!err) {
oss << &responsebuf;
boost::asio::async_read(socket, responsebuf,
boost::asio::transfer_at_least(1),
boost::bind(&AsioClient::handle_read_content,
this,
boost::asio::placeholders::error));
} else if(err == boost::asio::error::eof) {
// file end
qDebug() << oss.str().c_str() << endl;
emit read_finish(QString::fromStdString(oss.str()));
} else {
// error
emit read_failed(QString::fromStdString(err.message()));
}
}#ifndef ASIOCLIENT_H
#define ASIOCLIENT_H
#include <boost\asio.hpp>
#include <boost/bind.hpp>
#include <QObject>
#include <QString>
#include <memory>
#include <thread>
class AsioClient : public QObject
{
Q_OBJECT
public:
AsioClient();
virtual ~AsioClient();
void Get(const QString& url, const QString& path);
void handle_resolve(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
void handle_connect(const boost::system::error_code& err,
boost::asio::ip::tcp::resolver::iterator endpoint_iterator);
void handle_write(const boost::system::error_code& err);
void handle_read_line(const boost::system::error_code& err);
void handle_read_header(const boost::system::error_code& err);
void handle_read_content(const boost::system::error_code& err);
private:
boost::asio::io_service ioservice;
std::shared_ptr<boost::asio::io_service::work> work;
std::thread worker;
std::string server, path;
boost::asio::ip::tcp::resolver resolver;
boost::asio::ip::tcp::socket socket;
boost::asio::streambuf requestbuf;
boost::asio::streambuf responsebuf;
std::ostringstream oss;
signals:
void read_finish(const QString& msg);
void read_failed(const QString& msg);
};
#endif // ASIOCLIENT_H#include "widget.h"
#include "ui_widget.h"
#include "QString"
#include <QRegularExpression>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
, client(new AsioClient)
{
ui->setupUi(this);
ui->paramTable->setColumnCount(2);
ui->paramTable->setHorizontalHeaderLabels(QString("key;value").split(";"));
ui->paramTable->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->urlEdit->setText("http://127.0.0.1:5000/");
connect(client, SIGNAL(read_finish(QString)), this, SLOT(on_success));
}
Widget::~Widget()
{
delete ui;
delete client;
}
void Widget::on_getBtn_clicked()
{
QString url = ui->urlEdit->text();
// client->Get("www.boost.org","/");
// https://gist.github.com/voodooGQ/4057330
// ์ ์ฌ์ดํธ์์ ์๋์ ์ ๊ทํํ์์ ๋ฐ์์ ์ฌ์ฉํ๋ค.
// ์ฐธ๊ณ ๋ก ์ ๊ทํํ์ ํ์ธ์ฌ์ดํธ๋ https://regex101.com
QRegularExpression re("^(?:([A-Za-z]+):)?(\\/{0,3})([0-9.\\-A-Za-z]+)(?::(\\d+))?(?:\\/([^?#]*))?(?:\\?([^#]*))?(?:#(.*))?$");
QRegularExpressionMatch match = re.match(url);
if(match.hasMatch()) {
auto hostName = match.captured(3); // match 3์ด hostName
auto urlPath = "/" + match.captured(5); // match 5๊ฐ url
client->Get(hostName, urlPath);
}
}
void Widget::on_success(const QString& msg)
{
ui->responseEdit->setText(msg);
}