记录历史 QOS(BOOST/ASIO on TCP/UDP)限制每秒 RECEIVE ASYNC 的吞吐实现。

 本源文件实现仅供参考应用层实现QoS的一个实现,该实现是可用且正确的,但根据新的改进,不会再采纳这种不是很通用的实现,纵使它支持TCP、UDP。

头文件:

QoS.h

#pragma once

#include <ppp/stdafx.h>
#include <ppp/net/IPEndPoint.h>
#include <ppp/threading/Timer.h>

namespace ppp {
    namespace net {
        namespace asio {
            class QoS final : public std::enable_shared_from_this<QoS> {
            public:
                typedef std::recursive_mutex                                                                SynchronizedObject;
                typedef std::lock_guard<SynchronizedObject>                                                 SynchronizedObjectScope;
                typedef std::function<void(int sz)>                                                         ReceiveCallback;
                typedef std::function<void(int sz, boost::asio::ip::udp::endpoint&)>                        ReceiveFromCallback;
                struct ReceiveTransaction {
                public:
                    std::shared_ptr<boost::asio::ip::tcp::socket>                                           socket;
                    unsigned char*                                                                          buffer;
                    int                                                                                     offset;
                    int                                                                                     length;
                    bool                                                                                    demand;
                    std::shared_ptr<ReceiveCallback>                                                        callback;

                public:
                    typedef std::shared_ptr<ReceiveTransaction>                                             Ptr;
                };
                struct ReceiveFromTransaction {
                public:
                    std::shared_ptr<boost::asio::ip::udp::socket>                                           socket;
                    unsigned char*                                                                          buffer;
                    int                                                                                     offset;
                    int                                                                                     length;
                    std::shared_ptr<ReceiveFromCallback>                                                    callback;
                    boost::asio::ip::udp::endpoint*                                                         sourceEP;

                public:
                    typedef std::shared_ptr<ReceiveFromTransaction>                                         Ptr;
                };
                typedef std::unordered_map<boost::asio::ip::tcp::socket*, ReceiveTransaction::Ptr >         ReceiveTransactionTable;
                typedef std::unordered_map<boost::asio::ip::udp::socket*, ReceiveFromTransaction::Ptr>      ReceiveFromTransactionTable;

            public:
                QoS(int bandwidth) noexcept;
                ~QoS() noexcept;

            public:
                inline int                                                                                  GetBandwidth() noexcept { return this->_bandwidth; }
                inline void                                                                                 SetBandwidth(int bandwidth) noexcept {
                    this->_bandwidth = bandwidth < 1 ? 0 : bandwidth; // ReLU
                }
                inline bool                                                                                 IsDisposed() noexcept { return this->_disposed; }
                inline std::shared_ptr<QoS>                                                                 GetReference() noexcept { return this->shared_from_this(); }

            public:
                bool                                                                                        Initialize() noexcept;
                void                                                                                        Dispose() noexcept;
                bool                                                                                        Receive(
                    const std::shared_ptr<boost::asio::ip::tcp::socket>&                                    socket,
                    const void*                                                                             buffer,
                    int                                                                                     offset,
                    int                                                                                     length,
                    bool                                                                                    demand,
                    const std::shared_ptr<ReceiveCallback>&                                                 callback) noexcept;
                bool                                                                                        ReceiveFrom(
                    const std::shared_ptr<boost::asio::ip::udp::socket>&                                    socket,
                    const void*                                                                             buffer,
                    int                                                                                     offset,
                    int                                                                                     length,
                    boost::asio::ip::udp::endpoint&                                                         sourceEP,
                    const std::shared_ptr<ReceiveFromCallback>&                                             callback) noexcept;

            private:
                void                                                                                        Update() noexcept;
                bool                                                                                        IsPeek() noexcept;
                bool                                                                                        ReceiveImpl(
                    const std::shared_ptr<boost::asio::ip::tcp::socket>&                                    socket,
                    const void*                                                                             buffer,
                    int                                                                                     offset,
                    int                                                                                     length,
                    const std::shared_ptr<ReceiveTransaction>&                                              receive) noexcept;
                bool                                                                                        ReceiveFromImpl(
                    const std::shared_ptr<boost::asio::ip::udp::socket>&                                    socket,
                    const void*                                                                             buffer,
                    int                                                                                     offset,
                    int                                                                                     length,
                    boost::asio::ip::udp::endpoint&                                                         sourceEP,
                    const std::shared_ptr<ReceiveFromTransaction>&                                          receive) noexcept;

            private:
                SynchronizedObject                                                                          _syncobj;
                int                                                                                         _bandwidth;
                UInt64                                                                                      _per_seconds;
                std::atomic<bool>                                                                           _disposed;
                std::atomic<int>                                                                            _current_traffic;
                ReceiveTransactionTable                                                                     _recv_tcps;
                ReceiveFromTransactionTable                                                                 _recv_iips;
                std::shared_ptr<ppp::threading::Timer>                                                      _work_timer;
            };
        }
    }
}

源文件:

QoS.cpp

#include <ppp/stdafx.h>
#include <ppp/net/Socket.h>
#include <ppp/net/asio/QoS.h>
#include <ppp/threading/Timer.h>
#include <ppp/threading/Executors.h>

using ppp::threading::Timer;
using ppp::threading::Executors;

namespace ppp {
    namespace net {
        namespace asio {
            QoS::QoS(int bandwidth) noexcept
                : _bandwidth(0)
                , _per_seconds(0)
                , _disposed(false)
                , _current_traffic(0) {
                if (bandwidth < 1) {
                    bandwidth = 0;
                }
                this->_bandwidth = bandwidth;
            }

            QoS::~QoS() noexcept {
                this->Dispose();
            }

            void QoS::Dispose() noexcept {
                std::vector<std::shared_ptr<ReceiveFromTransaction> > recv_iips;
                std::vector<std::shared_ptr<ReceiveTransaction> > recv_tcps;
                if (!this->_disposed.exchange(true)) {
                    SynchronizedObjectScope scope(this->_syncobj);
                    ReceiveTransactionTable::iterator recv_tcps_tail = this->_recv_tcps.begin();
                    ReceiveTransactionTable::iterator recv_tcps_endl = this->_recv_tcps.end();
                    for (; recv_tcps_tail != recv_tcps_endl; recv_tcps_tail++) {
                        recv_tcps.push_back(std::move(recv_tcps_tail->second));
                    }

                    ReceiveFromTransactionTable::iterator recv_iips_tail = this->_recv_iips.begin();
                    ReceiveFromTransactionTable::iterator recv_iips_endl = this->_recv_iips.end();
                    for (; recv_iips_tail != recv_iips_endl; recv_iips_tail++) {
                        recv_iips.push_back(std::move(recv_iips_tail->second));
                    }

                    this->_recv_tcps.clear();
                    this->_recv_iips.clear();
                }

                for (size_t i = 0, count = recv_tcps.size(); i < count; i++) {
                    const std::shared_ptr<ReceiveTransaction>& r = recv_tcps[i];
                    if (NULL != r) {
                        (*r->callback)(-1);
                    }
                }

                for (size_t i = 0, count = recv_iips.size(); i < count; i++) {
                    const std::shared_ptr<ReceiveFromTransaction>& r = recv_iips[i];
                    if (NULL != r) {
                        (*r->callback)(-1, *r->sourceEP);
                    }
                }
            }

            bool QoS::Initialize() noexcept {
                SynchronizedObjectScope scope(this->_syncobj);
                if (this->IsDisposed()) {
                    return false;
                }

                std::shared_ptr<Timer> t = this->_work_timer;
                if (NULL != t) {
                    return false;
                }

                int bandwidth = this->_bandwidth;
                if (bandwidth < 1) {
                    return true;
                }
                else {
                    this->_per_seconds = Executors::GetTickCount();
                }

                std::shared_ptr<QoS> self = this->GetReference();
                t = make_shared_object<ppp::threading::Timer>(Executors::GetDefault());
                t->TickEvent = make_shared_object<Timer::TickEventHandler>(
                    [self, this](Timer* sender, Timer::TickEventArgs& e) noexcept {
                        this->Update();
                    });
                t->SetInterval(10);
                t->Start();
                this->_work_timer = std::move(t);

                return true;
            }

            bool QoS::IsPeek() noexcept {
                int bandwidth = this->_bandwidth;
                if (bandwidth < 1) {
                    return false;
                }

                int traffic = this->_current_traffic;
                return traffic >= bandwidth;
            }

            void QoS::Update() noexcept {
                std::vector<std::shared_ptr<ReceiveFromTransaction> > recv_iips;
                std::vector<std::shared_ptr<ReceiveTransaction> > recv_tcps;
                do {
                    SynchronizedObjectScope scope(this->_syncobj);
                    do {
                        UInt64 now = Executors::GetTickCount();
                        if ((this->_per_seconds / 1000) == (now / 1000)) {
                            return;
                        }

                        this->_per_seconds = now;
                    } while (false);

                    this->_current_traffic = 0;
                    for (; ;) {
                        ReceiveTransactionTable::iterator tail = this->_recv_tcps.begin();
                        ReceiveTransactionTable::iterator endl = this->_recv_tcps.end();
                        if (tail == endl) {
                            break;
                        }

                        std::shared_ptr<ReceiveTransaction> r = tail->second;
                        this->_recv_tcps.erase(tail);
                        if (!this->ReceiveImpl(r->socket, r->buffer, r->offset, r->length, r)) {
                            recv_tcps.push_back(std::move(r));
                        }
                    }

                    this->_recv_tcps.clear();
                    for (; ;) {
                        ReceiveFromTransactionTable::iterator tail = this->_recv_iips.begin();
                        ReceiveFromTransactionTable::iterator endl = this->_recv_iips.end();
                        if (tail == endl) {
                            break;
                        }

                        std::shared_ptr<ReceiveFromTransaction> r = tail->second;
                        this->_recv_iips.erase(tail);
                        if (!this->ReceiveFromImpl(r->socket, r->buffer, r->offset, r->length, *r->sourceEP, r)) {
                            recv_iips.push_back(std::move(r));
                        }
                    }
                    this->_recv_iips.clear();
                } while (false);

                for (size_t i = 0, count = recv_tcps.size(); i < count; i++) {
                    const std::shared_ptr<ReceiveTransaction>& r = recv_tcps[i];
                    if (NULL != r) {
                        (*r->callback)(0);
                    }
                }

                for (size_t i = 0, count = recv_iips.size(); i < count; i++) {
                    const std::shared_ptr<ReceiveFromTransaction>& r = recv_iips[i];
                    if (NULL != r) {
                        (*r->callback)(0, *r->sourceEP);
                    }
                }
            }

            bool QoS::ReceiveImpl(
                const std::shared_ptr<boost::asio::ip::tcp::socket>&                                socket,
                const void*                                                                         buffer,
                int                                                                                 offset,
                int                                                                                 length,
                const std::shared_ptr<ReceiveTransaction>&                                          receive) noexcept {

                if (!socket->is_open()) {
                    return false;
                }

                std::shared_ptr<QoS> self = this->GetReference();
                std::shared_ptr<ReceiveTransaction> receive_ = receive;
                if (receive_->demand) {
                    boost::asio::async_read(*socket.get(), boost::asio::buffer((char*)buffer + offset, length),
                        [self, this, receive_](const boost::system::error_code& ec, UInt32 sz) noexcept {
                            int by = std::max<int>(-1, ec ? -1 : sz);
                            if (by > 0) {
                                this->_current_traffic += by;
                            }
                            (*receive_->callback)(by);
                        });
                }
                else {
                    socket->async_read_some(boost::asio::buffer((char*)buffer + offset, length),
                        [self, this, receive_](const boost::system::error_code& ec, UInt32 sz) noexcept {
                            int by = std::max<int>(-1, ec ? -1 : sz);
                            if (by > 0) {
                                this->_current_traffic += by;
                            }
                            (*receive_->callback)(by);
                        });
                }
                return true;
            }

            bool QoS::Receive(
                const std::shared_ptr<boost::asio::ip::tcp::socket>& socket,
                const void* buffer,
                int                                                                                 offset,
                int                                                                                 length,
                bool                                                                                demand,
                const std::shared_ptr<ReceiveCallback>&                                             callback) noexcept {

                if (this->IsDisposed()) {
                    return false;
                }

                if (socket == NULL || callback == NULL || !socket->is_open()) {
                    return false;
                }

                if (this->_bandwidth < 1) {
                    std::shared_ptr<ReceiveTransaction> r = make_shared_object<ReceiveTransaction>();
                    r->socket = socket;
                    r->buffer = (unsigned char*)buffer;
                    r->offset = offset;
                    r->length = length;
                    r->callback = callback;
                    r->demand = demand;
                    return this->ReceiveImpl(socket, buffer, offset, length, r);
                }

                if (buffer == NULL && (offset != 0 || length != 0)) {
                    return false;
                }

                if (offset < 0 || length < 0) {
                    return false;
                }

                std::shared_ptr<ReceiveTransaction> r;
                do {
                    SynchronizedObjectScope scope(this->_syncobj);
                    ReceiveTransactionTable::iterator tail = this->_recv_tcps.find(socket.get());
                    ReceiveTransactionTable::iterator endl = this->_recv_tcps.end();
                    if (tail != endl) {
                        return false;
                    }

                    r = make_shared_object<ReceiveTransaction>();
                    r->socket = socket;
                    r->buffer = (unsigned char*)buffer;
                    r->offset = offset;
                    r->length = length;
                    r->callback = callback;
                    r->demand = demand;
                    if (this->IsPeek()) {
                        this->_recv_tcps[socket.get()] = r;
                        return true;
                    }
                } while (false);
                return this->ReceiveImpl(socket, buffer, offset, length, r);
            }

            bool QoS::ReceiveFromImpl(
                const std::shared_ptr<boost::asio::ip::udp::socket>&                                socket,
                const void*                                                                         buffer,
                int                                                                                 offset,
                int                                                                                 length,
                boost::asio::ip::udp::endpoint&                                                     sourceEP,
                const std::shared_ptr<ReceiveFromTransaction>&                                      receive) noexcept {

                if (!socket->is_open()) {
                    return false;
                }

                std::shared_ptr<QoS> self = this->GetReference();
                std::shared_ptr<ReceiveFromTransaction> receive_ = receive;
                socket->async_receive_from(boost::asio::buffer((char*)buffer + offset, length), sourceEP,
                    [self, this, receive_](const boost::system::error_code& ec, UInt32 sz) noexcept {
                        int by = std::max<int>(-1, ec ? -1 : sz);
                        if (by > 0) {
                            this->_current_traffic += by;
                        }
                        (*receive_->callback)(by, *receive_->sourceEP);
                    });
                return true;
            }

            bool QoS::ReceiveFrom(
                const std::shared_ptr<boost::asio::ip::udp::socket>&                                socket,
                const void*                                                                         buffer,
                int                                                                                 offset,
                int                                                                                 length,
                boost::asio::ip::udp::endpoint&                                                     sourceEP,
                const std::shared_ptr<ReceiveFromCallback>&                                         callback) noexcept {

                if (this->IsDisposed()) {
                    return false;
                }

                if (socket == NULL || callback == NULL || !socket->is_open()) {
                    return false;
                }

                if (this->_bandwidth < 1) {
                    std::shared_ptr<ReceiveFromTransaction> r = make_shared_object<ReceiveFromTransaction>();
                    r->socket = socket;
                    r->buffer = (unsigned char*)buffer;
                    r->offset = offset;
                    r->length = length;
                    r->callback = callback;
                    r->sourceEP = std::addressof(sourceEP);
                    return this->ReceiveFromImpl(socket, buffer, offset, length, sourceEP, r);
                }

                if (buffer == NULL && (offset != 0 || length != 0)) {
                    return false;
                }

                if (offset < 0 || length < 0) {
                    return false;
                }

                std::shared_ptr<ReceiveFromTransaction> r;
                do {
                    SynchronizedObjectScope scope(this->_syncobj);
                    ReceiveFromTransactionTable::iterator tail = this->_recv_iips.find(socket.get());
                    ReceiveFromTransactionTable::iterator endl = this->_recv_iips.end();
                    if (tail != endl) {
                        return false;
                    }

                    r = make_shared_object<ReceiveFromTransaction>();
                    r->socket = socket;
                    r->buffer = (unsigned char*)buffer;
                    r->offset = offset;
                    r->length = length;
                    r->callback = callback;
                    r->sourceEP = std::addressof(sourceEP);
                    if (this->IsPeek()) {
                        this->_recv_iips[socket.get()] = r;
                        return true;
                    }
                } while (false);
                return this->ReceiveFromImpl(socket, buffer, offset, length, sourceEP, r);
            }
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值