VC++ Windows 平台通过QOS2库函数设置Socket DSCP(IP_TOS)参数选项

本体提供的函数实现,只能对于TCP生效,UDP没法生效,看文档没搞明白,有了解UDP怎么设置DSCP的童鞋,可以在评论区给予答复。

用法是这样的,每个TCP在建立链接后,立即创建这个QOSS的实例,当然也可以在链接前,但在连接前有一定限制就是说,你必须在连接前把IP+PORT地址传进去,链接建立后在创建QOS就不需要传入IP+PORT地址。

同时,在关联的TCP链接关闭时需要销毁这个,否则就会产生QOS2内核句柄资源泄漏。

DSCP值26,就等于 IP_TOS: 0x68,即FLASH,[IPTOS_LOWDELAY] 宏的效果【MACOS/LINUX】上,Windows 平台被微软禁用支援了。

头文件声明:

cpp 复制代码
        class QoSS final
        {
        public:
            QoSS(int fd) noexcept;
            ~QoSS() noexcept;

        public:
            static std::shared_ptr<QoSS>            New(int fd, const boost::asio::ip::address& host, int port) noexcept { return New(fd, host, port, false); }
            static std::shared_ptr<QoSS>            New(int fd) noexcept { return New(fd, boost::asio::ip::address_v4::any(), 0, true); }

        private:
            static std::shared_ptr<QoSS>            New(int fd, const boost::asio::ip::address& host, int port, bool noaddress) noexcept;

        private:
            int                                     fd_ = -1;
            void*                                   h_  = NULL;
            DWORD                                   f_  = 0;
        };

源文件:

cpp 复制代码
        QoSS::QoSS(int fd) noexcept
            : fd_(fd)
            , h_(NULL)
            , f_(NULL)
        {

        }

        QoSS::~QoSS() noexcept
        {
            if (NULL != h_)
            {
                if (f_ != 0)
                {
                    QOSRemoveSocketFromFlow(h_, fd_, f_, 0);
                }

                QOSCloseHandle(h_);
            }
        }

        std::shared_ptr<QoSS> QoSS::New(int fd, const boost::asio::ip::address& host, int port, bool noaddress) noexcept
        {
            if (fd == INVALID_SOCKET)
            {
                return NULL;
            }

            std::shared_ptr<QoSS> qos = make_shared_object<QoSS>(fd);
            if (NULL == qos)
            {
                return NULL;
            }

            QOS_VERSION ver = { 1, 0 };
            if (!QOSCreateHandle(&ver, &qos->h_))
            {
                return NULL;
            }

            if (noaddress)
            {
                if (!QOSAddSocketToFlow(qos->h_, fd, NULL, QOSTrafficTypeControl, QOS_NON_ADAPTIVE_FLOW, &qos->f_))
                {
                    return NULL;
                }
            }
            else
            {
                if (port <= IPEndPoint::MinPort || port > IPEndPoint::MaxPort)
                {
                    return NULL;
                }

                if (!host.is_v4() && !host.is_v6())
                {
                    return NULL;
                }

                if (IPEndPoint::IsInvalid(host))
                {
                    return NULL;
                }

                if (host.is_v4())
                {
                    sockaddr_in in{};
                    in.sin_family = AF_INET;
                    in.sin_port = htons(port);
                    in.sin_addr.s_addr = htonl(host.to_v4().to_uint());

                    if (!QOSAddSocketToFlow(qos->h_, fd, reinterpret_cast<sockaddr*>(&in), QOSTrafficTypeControl, QOS_NON_ADAPTIVE_FLOW, &qos->f_))
                    {
                        return NULL;
                    }
                }
                else
                {
                    sockaddr_in6 in6{};
                    in6.sin6_family = AF_INET6;
                    in6.sin6_port = htons(port);
                    memcpy(&in6.sin6_addr, host.to_v6().to_bytes().data(), sizeof(in6.sin6_addr));

                    if (!QOSAddSocketToFlow(qos->h_, fd, reinterpret_cast<sockaddr*>(&in6), QOSTrafficTypeControl, QOS_NON_ADAPTIVE_FLOW, &qos->f_))
                    {
                        return NULL;
                    }
                }
            }

            // We shift the complete ToS value by 3 to get rid of the 3 bit ECN field
            DWORD dscp = 26;

            // Sets DSCP to the same as Linux
            // This will fail if we're not admin, but we ignore it
            if (!QOSSetFlow(qos->h_, qos->f_, QOSSetOutgoingDSCPValue, sizeof(DWORD), &dscp, 0, NULL))
            {
                return NULL;
            }

            return qos;
        }

参考文档:

https://learn.microsoft.com/en-us/windows/win32/winsock/ipproto-ip-socket-options#windows-support-for-ip_proto-options

https://learn.microsoft.com/en-us/windows-server/networking/technologies/qos/qos-policy-manage#advanced-qos-settings-dscp-marking-override

https://learn.microsoft.com/en-us/windows-server/networking/technologies/qos/qos-policy-manage#advanced-qos-settings-dscp-marking-override

https://learn.microsoft.com/en-us/previous-versions/windows/desktop/dd874008(v=vs.85)

相关推荐
sunfove9 小时前
光网络的立交桥:光开关 (Optical Switch) 原理与主流技术解析
网络
Kevin Wang72712 小时前
欧拉系统服务部署注意事项
网络·windows
min18112345612 小时前
深度伪造内容的检测与溯源技术
大数据·网络·人工智能
汤愈韬12 小时前
NAT策略
网络协议·网络安全·security·huawei
汤愈韬12 小时前
Full Cone Nat
网络·网络协议·网络安全·security·huawei
zbtlink12 小时前
现在还需要带电池的路由器吗?是用来干嘛的?
网络·智能路由器
桌面运维家13 小时前
vDisk配置漂移怎么办?VOI/IDV架构故障快速修复
网络·架构
dalerkd13 小时前
忙里偷闲叙-谈谈最近两年
网络·安全·web安全
汤愈韬13 小时前
NAT ALG (应用层网关)
网络·网络协议·网络安全·security·huawei
运维栈记15 小时前
虚拟化网络的根基-网络命名空间
网络·docker·容器