用Qt实现一个桌面弹幕程序(二)--实现一个弹幕②



  • 现在就一起来愉快地编写一个弹幕类吧

    杰洛君 以单身多年的手速很快地 右键 点击项目 新建 了一个Danmu.h 和 Danmu.cpp 文件<( ̄︶ ̄)>

    熟悉C++的你,一定知道接下来就是编写弹幕类的时候了!

    这个弹幕类是重载QLabel的,所以它的类至少应该是这个样子:

    #ifndef DANMU_H
    #define DANMU_H
    
    #include <QLabel>
    
    class Danmu : public QLabel{
    
        Q_OBJECT
    
      public:
    
      Danmu(QWidget * parent);       //构造函数
    
      ~Danmu();     //析构函数
    
      public slots:
    
      private:
    };
    
    #endif // DANMU_H
    

    按照上一篇文章中我们提到了弹幕的好几种属性:

    • 自己的文字内容
    • 自己的字体
    • 自己的颜色
    • 自己的大小
    • 自己的飞行快慢
    • 自己的透明度

    于是在这个类中应该有对应的私有属性:

    • QString 类型的 DText属性
    • QFont 类型的danmuFont属性
    • QColor 类型的qcolor属性
    • int 类型的宽度和高度
    • int 类型的 runTime 持续时间属性
    • double 类型的Transparency属性

    当然,杰洛君后来又想到了一些属性,于是也添加进来:

    • int 类型的 type属性-- --用于区分横飞的弹幕与置顶以及位于底部的弹幕
    • int 类型的PosX与PosY属性-- --用于记录弹幕的初始位置~

    于是乎你的弹幕类中的私有属性至少应该是这样子的:

          int PosX;
          int PosY;
          QString DText;
          QString color;  //这个color属性保存英文颜色字符串
          QColor qcolor;
          int type;
          QFont danmuFont;
          int DHeight;
          double Transparency;
          int runTime;
    

    由于写过一段时间的JavaEE,杰洛君本能地为这些属性写了响应的Get和Set方法<( ̄ˇ ̄)/

    什么是Get和Set方法?
    就是为每个私有成员设置公有的设置和获取方法
    例如:
    void setColor(QString color);
    QString getColor();

    当然你也写成用c++风格的get方法 QString Color();

    小A : 类里的方法都是可以直接访问私有成员的呀,这有什么必要吗?

    杰洛君: 额额,确实可以直接访问,写Get和Set方法是个人编程习惯啦= ̄ω ̄=

    有了这么多私有变量,自然构造函数就要更加复杂啦,但是看到PosX 和 PosY 属性的时候,杰洛君呆住了。。。{{{(>_<)}}} 弹幕的起点怎么确定呀?

    如何确定弹幕的起始位置?

    弹幕是从哪里开始飞的呢?

    小A:简单,从屏幕的最右边开始呗~

    确实,弹幕从屏幕的外部飞入,那么这个具体位置该怎么设置呢,设置一个定值?比如分辨率为800720 那就设置 900吧,这样看起来就是从屏幕外侧飞进来了,那如果是1366768呢?900不就不够了吧。。。

    于是乎获取屏幕的分辨率成为我们要解决的一个问题。

    幸好Qt已经为我们做好了这些工作:

    在Danmu包含的头文件中加入 QRect 与 QDesktopWidget吧~

    QDesktopWidget* desktopWidget;  //获取桌面设备  
    QRect screenRect;
    desktopWidget = QApplication::desktop(); //获取桌面Widget
    screenRect = desktopWidget->screenGeometry(); //获取桌面大小的矩形
    

    这样我们就获得了桌面大小的这样的一个矩形,可以获得它的长和宽,利用这点就可以确定出起始位置的设置方法,保证不同电脑上弹幕的起始位置都在屏幕外。

    于是,杰洛君在Danmu的私有成员中加入了一个QRect 类型的 screenRect属性,这下你知道这个矩形是做什么用的了吧~

    如何确定弹幕的高度和宽度?

    弹幕只有一行内容所以它的高度是单个字的高度,这个几乎可以说是固定的,但是它的长度就不是固定的了,随用户输入字数多少而变化。

    这时如果能够根据内容的多少知道我们的字体会有多长该有多好呀~

    好在Qt 也为我们做好这个工作

    利用QFontMetrics类中的 int QFontMetrics::width(const QString & text, int len = -1) const方法 可以获得一段字符串的像素长度。

    具体用法:

    QFontMetrics metrics(this->getQFont()); //传入一个QFont字体
    metrics.height(); //得到字体高度
    metrics.width(DText); //获得DText字符串的像素宽度
    this->setFixedHeight(metrics.height()+5); //弹幕设置固定的高度
    this->setFixedWidth(metrics.width(DText)+4); //弹幕设置固定的宽度

    如果你觉得不保险,可以在这基础上再加上一些整数,因为背景是透明的,所以只要字体显示完整就可以了

    如何绘制弹幕内容?

    上篇文章中我们用到了 QPalette 改变弹幕的颜色,通过改变字体去改变弹幕的大小。

    但是这个效果其实并不好,没有描边,看起来就是不像弹幕。

    于是,杰洛君决定重载 弹幕的 绘制函数 重绘出我们需要的效果来。

    首先在 Danmu类中添加 :

    protected:
          void paintEvent(QPaintEvent *);       //弹幕的绘制函数
    

    这个是重载了QLabel的绘制函数,在接收到绘制时间信号时会调用这个方法。

    下面是它的实现:

    void Danmu::paintEvent(QPaintEvent *){  //弹幕绘制函数
            QPainter painter(this);     //以弹幕窗口为画布
            painter.save();
            QFontMetrics metrics(this->getQFont());     //获取弹幕字体
            QPainterPath path;      //描绘路径用
            QPen pen(QColor(0, 0, 0, 230));       //自定义画笔的样式,让文字周围有边框
            painter.setRenderHint(QPainter::Antialiasing);  //反走样
            int penwidth = 4;  //设置描边宽度
            pen.setWidth(penwidth);
            int len = metrics.width(DText);
            int w = this->width();
            int px = (len - w) / 2;
            if(px < 0)
            {
                px = -px;
            }
            int py = (height() - metrics.height()) / 2 + metrics.ascent();
            if(py < 0)
            {
                py = -py;
            }
            path.addText(px+2,py+2,this->getQFont(),DText);     //画字体轮廓
            painter.strokePath(path, pen);  //描边
            painter.drawPath(path);  //画路径
            painter.fillPath(path, QBrush(this->getQColor()));      //用画刷填充
            painter.restore();
    }
    

    这里用到了QPainter类,这个类很重要,建议多看看文档,熟悉熟悉它的用法。有机会杰洛君会找几个例子好好描述它。

    这里比较难理解的是py的计算,里面用到了 metrics.ascent(),这个是什么呢?杰洛君通过F1的帮忙知道了这个是什么。

    int QFontMetrics::ascent() const
    The ascent of a font is the distance from the baseline to the highest position characters extend to.

    ascent 就是字体的最高位置到字体基线这么一段距离。

    所以py的计算就是 弹幕窗体的高度 - 字体的高度 得到留白的大小,这个留白大小平均分之后 再加上 基线以上的字体高度,得到真正绘制字体的位置。

    小C:你这么说,我怎么懂呀。。。

    确实用杰洛君拙劣的文字描述很难懂,怎么办呢?下面就看看文档的图示吧~

    0_1456660335692_pic13.png

    从这张图中我们可以清晰地看到基线并不是文字的最下方。这么看是不是好懂些了。

    如何让弹幕飞行?

    好了,杰洛君知道屏幕左上角为(0,0)位置,利用上述的屏幕矩形,把弹幕的起始横向位置设置为 矩形宽度加上 200 或者 随机某个整数,这样弹幕的横向位置就看起来比较随机了。

    而纵向设置为 屏幕宽度 以内的随机整数,这样竖直方向的弹幕看起来也就比较随机了。

    (p.s.其实范围应该是屏幕高度减去字体高度,小伙伴们可以想一想这是为什么?)

    如何生成随机数?
    就像c++中有srand() 和 rand()函数一样,Qt 有 qsrand() 和 qrand() 函数
    具体用法:
    头文件加上QTime
    qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
    int y = qrand()%rect.height(); //得到矩形高度范围内的一个随机数

    问题来了,弹幕如何才能做到飞行?

    方案 1:

    使用Qt 的 QTimer定时器,每隔20ms 调用一个槽函数
    这个槽函数做弹幕X方向坐标递减,然后弹幕 move到相应的位置
    重绘
    判断是否飞离屏幕,若飞离则析构弹幕。

    对于这个方案,确实可行,效果也不错,但是有一个问题就是,弹幕一旦多起来就会看起来很卡。

    (不要问杰洛君是怎么知道的ヽ(≧□≦)ノ)

    方案 2:

    弹幕移动就是一个动画,那就用Qt 的QPropertyAnimation吧~
    确定起始位置,终点位置和持续时间
    启动动画
    动画结束时就析构弹幕

    恩恩,方案二看起来更好呀,那就用它吧~(^__^)

    QPropertyAnimation * anim2=new QPropertyAnimation(this, "pos");
    anim2->setStartValue(QPoint(this->getPosX(),this->getPosY()));
    anim2->setEndValue(QPoint(-(this->width()), this->getPosY()));
    anim2->setDuration(this->getRunTime());
    anim2->setEasingCurve(QEasingCurve::Linear);
    this->setWindowOpacity(this->getTransparency());
    this->show();
    anim2->start();
           
    //利用Qt的信号和槽函数响应机制,让动画销毁时 弹幕 析构       
    
    connect(anim2,SIGNAL(finished()),this,SLOT(deleteLater()));
    

    上面这段代码应该放在哪里呢?杰洛君把它放在了Danmu的构造函数中。

    或许你会觉得anim2这个指针只有new 没有 delete 存在内存泄漏。

    不过Qt 拥有一个机制,那就是如果该对象为QObject的派生类,销毁父对象时会销毁它的子对象,而我们的动画对象是有声明父对象的,所以析构弹幕时动画也会销毁。

    千辛万苦终于走到这步

    好了,细节设计好了,就设计一下构造函数吧~

    Danmu(
    QWidget * parent,
    QString text,
    QString color,
    int type,
    QRect rect,
    QFont danmuFont = QFont("SimHei",20,100),
    double Transparency = 1.00,
    int runTime=15000
    );       //构造函数,常用
    

    在构造函数中,带有默认参数,这样可以减轻很多工作量。

    ###具体Danmu.h头文件实现:

    #ifndef DANMU_H
    #define DANMU_H
    
    #include <QLabel>
    #include <QRect>
    #include <QColor>
    #include <QDebug>
    #include <QTextCharFormat>
    #include <QPainter>
    #include <iostream>
    #include <QTime>
    #include <QPropertyAnimation>
    #include <QParallelAnimationGroup>
    class Danmu : public QLabel{
    
        Q_OBJECT
    
      public:
    
          Danmu(QWidget * parent,QString text,QString color,int type,QRect rect,QFont danmuFont = QFont("SimHei",20,100),double Transparency = 1.00,int runTime=15000);       //构造函数,常用
    
          ~Danmu();     //析构函数
    
          //一些成员变量的Get方法与Set方法
          //全部放上来会显得累赘所以略去
    
      protected:
          void paintEvent(QPaintEvent *);       //重点,弹幕的绘制函数
    
      private:
          int PosX;
          int PosY;
          QString DText;
          QString color;
          QColor qcolor;
          int type;
          QFont danmuFont;
          int DHeight;
          double Transparency;
          QRect screenrect;
          QPropertyAnimation *anim2;
          int runTime;
    };
    
    #endif // DANMU_H
    

    ###具体Danmu.cpp文件实现:

    #include "Danmu.h"
    
    Danmu::Danmu(QWidget * parent,QString text,QString color,int type,QRect rect,QFont danmuFont,double Transparency,int runTime):QLabel(parent){
        DText = text;
        //this->setText(text);        //设置内容
        this->setColor(color);      //设置内容
        this->setType(type);        //设置类型
        this->setQFont(danmuFont);      //弹幕字体
        this->setTransparency(Transparency);        //弹幕透明度
        this->setRunTime(runTime);
        this->setScreenRect(rect);
        QFontMetrics metrics(this->getQFont());
        QPalette palll=QPalette();
        QString DColor = this->getColor();
        anim2 = NULL;
        //颜色字符串转化为特定的颜色
        if(DColor == "White"){
            palll.setColor(QPalette::WindowText,QColor(255,255,246,255));
            this->setQColor(QColor(255,255,246,255));
        }else if(DColor =="Red"){
            palll.setColor(QPalette::WindowText,QColor(231,0,18,255));
            this->setQColor(QColor(231,0,18,255));
        }else if(DColor =="Yellow"){
            palll.setColor(QPalette::WindowText,QColor(254,241,2,255));
            this->setQColor(QColor(254,241,2,255));
        }else if(DColor =="Brown"){
            palll.setColor(QPalette::WindowText,QColor(149,119,57,255));
            this->setQColor(QColor(149,119,57,255));
        }else{
            palll.setColor(QPalette::WindowText,QColor(255,255,246,255));
            this->setQColor(QColor(255,255,246,255));
        }
        this->setPalette(palll);        //设置调色盘
        this->setFixedHeight(metrics.height()+5);
        this->setFixedWidth(metrics.width(DText)+4);
        int yy = qrand()%rect.height(); //临时的位置,还要防止高度在屏幕下导致显示不完整
        int y = yy<(rect.height()-metrics.height()-5)?(yy):(rect.height()-metrics.height()-5);
        int xx = rect.width()+qrand()%500;
        this->move(xx,y);
        this->setPosX(xx);//设置弹幕水平的位置
        this->setPosY(y);       //设置弹幕垂直位置
    
        this->setWindowFlags(Qt::FramelessWindowHint|Qt::Tool|Qt::WindowStaysOnTopHint);    //设置弹幕为无窗口无工具栏且呆在窗口顶端
    
        this->setAttribute(Qt::WA_TranslucentBackground, true);
        this->setFocusPolicy(Qt::NoFocus);
        this->hide();
        anim2=new QPropertyAnimation(this, "pos");
        anim2->setDuration(this->getRunTime());
        anim2->setStartValue(QPoint(this->getPosX(),this->getPosY()));
        anim2->setEndValue(QPoint(-(this->width()), this->getPosY()));
        anim2->setEasingCurve(QEasingCurve::Linear);
        this->setWindowOpacity(this->getTransparency());
        this->show();
        this->repaint();
        anim2->start();
            //connect(anim2,SIGNAL(finished()),this,SLOT(deleteLater()));
    }
    
    void Danmu::paintEvent(QPaintEvent *){  //弹幕绘制函数
            QPainter painter(this);     //以弹幕窗口为画布
            painter.save();
            QFontMetrics metrics(this->getQFont());     //获取弹幕字体
            QPainterPath path;      //描绘路径用
            QPen pen(QColor(0, 0, 0, 230));       //自定义画笔的样式,让文字周围有边框
            painter.setRenderHint(QPainter::Antialiasing);
            int penwidth = 4;
            pen.setWidth(penwidth);
            int len = metrics.width(DText);
            int w = this->width();
            int px = (len - w) / 2;
            if(px < 0)
            {
                px = -px;
            }
            int py = (height() - metrics.height()) / 2 + metrics.ascent();
            if(py < 0)
            {
                py = -py;
            }
            path.addText(px+2,py+2,this->getQFont(),DText);     //画字体轮廓
            painter.strokePath(path, pen);
            painter.drawPath(path);
            painter.fillPath(path, QBrush(this->getQColor()));      //用画刷填充
            painter.restore();
    }
    
    
    
    Danmu::~Danmu(){
        qDebug()<<"弹幕被析构"<<endl;
    }
    
    //下面是get和set方法的实现
    //同样全部放上无法凸显重点故略去
    
    
    

    上面就是具体代码了,这段代码有很多可以优化的地方。

    其中那一大段if else 想必会被很多人唾弃吧。

    不过还请体谅体谅杰洛君,这个可怜的娃为了实现这么小一个功能已经耗尽脑筋,放弃思考了〒▽〒。

    有时间会采用enum与switch-case做替换的。

    至于颜色的取值,大家可以找一些简单的取色软件获取颜色的16位值或者RGB值

    关于最终程序中用到的颜色,这里给个参考:

    • "White" QColor(255,255,246,255));
    • "Red" QColor(231,0,18,255));
    • "Yellow" QColor(254,241,2,255));
    • "Green" QColor(0,152,67,255));
    • "Blue" QColor(0,160,234,255));
    • "Pink" QColor(226,2,127,255));
    • "Grass" QColor(144,195,32,255));
    • "DBlue" QColor(0,46,114,255));
    • "DYellow" QColor(240,171,42,255));
    • "DPurple" QColor(104,58,123,255));
    • "LBlue" QColor(129,193,205,255));
    • "Brown" QColor(149,119,57,255));

    这些颜色的值都取自B站手机客户端上的可选颜色~

    在main函数中试一试吧

    int main(int argc, char *argv[])
    {
        QApplication a(argc, argv);
        MainWindow w;
        qsrand(QTime(0,0,0).secsTo(QTime::currentTime()));
        QDesktopWidget* desktopWidget;                                    //获取桌面设备
        QRect screenRect;
        desktopWidget = QApplication::desktop();                   //获取桌面设备
        screenRect = desktopWidget->screenGeometry();              //获取桌面大小的矩形
        Danmu danmu(NULL,"Hello World","Red",1,screenRect);
        w.show();
    
        return a.exec();
    }
    

    不出意外你就会看到一个弹幕飞过了,啊啊啊,终于成功了!!!ค(TㅅT)

    杰洛君已经哭成狗狗了。。。

    你会看到那个动画那段connect代码被注释了。

    这是因为启用这段代码,动画结束后就会析构弹幕,但是我们的弹幕不是在堆上新建的对象,所以delete一个栈上的对象 退出程序时,这个弹幕的析构函数将被再次调用,一个对象调用了两次析构函数,程序当然就瞬间爆炸了。

    所以注释了这段代码,这个不是大问题,只用new的方式建立Danmu对象就可以启用这段代码了。

    后续

    实现了一个弹幕了,但是后续问题接踵而至。

    弹幕失去控制了!!!

    我想隐藏它该怎么办?

    弹幕好污好羞耻又该如何监控。

    放心,后续都会讲到的,今天就到这里吧~O(∩_∩)O哈哈~

    或许你会觉得杰洛君废话很多,不过这些废话姑且算是自己的思考过程进去,希望你们会喜欢~。

    题外话
    本来博文早上应该就可以发的了,不过我认识的一位会画画的女神大大上午指导我画画去了~

    0_1456661850900_draw.jpg

    我只能表示:

    手残党上女神的课一上午,胜过画室苦画三年呀!



  • @杰洛飞 说:

    弹幕是从哪里开始飞的呢?

    小A:简单,从屏幕的最左边开始呗~

    不对啊。应该从屏幕的最右边飞啊。



  • 最后这个线稿画得很棒!



  • @jiangcaiyang 对对对,我改改



  • @jiangcaiyang 谢谢☺ 会继续把它练好~



  • 啪啪啪,写的不错。弹幕解析那一块,能不能直接解析b站的弹幕文件?最后线稿不错。



  • @qyvlik 这个没有做哦,不过可以作为这个程序的一个拓展方向,有机会会试试,嘿嘿😝



  • @杰洛飞 好好好。



  • 最后的手绘是本文一大亮点 -。-



  • 不是很明白,什么叫做“弹幕类”?它的目的是什么?



  • @stlcours 弹幕就是 类似 文字跑马灯效果,也就是通常情况下让文字从右往左进行移动。这个效果呢,实现起来很简单,也可以用Qt Quick以及Qt Widgets实现。



  • 用Label性能会比较悲催
    建议从qtquick的Text做起可能比较好



  • @MidoriYakumo

    嘿嘿嘿, DarkFlameMaster 这个是用 QML 实现的弹幕播放器,不过在弹幕轨迹分配和弹幕播放器中的时间轴算法找不到其他可以参考的。有什么好的相关文章推荐吗?



  • 没研究过诶,你那个有什么问题么?


Log in to reply
 

走马观花

最近的回复

  • C

    Qt for MCU需要商业授权的

    read more
  • Qt for MCUs

    搭建Qt for MCUs PC端开发环境。qt for mcus提供了一个完整的图形框架和工具包,包含了在MCUs上设计、开发和部署gui所需的一切。它允许您在裸机或实时操作系统上运行应用程序。

    先决条件

    开发主机环境支持仅限于Windows 10

    MSVC compiler v19.16 (Visual Studio 2017 15.9.9 or newer) x64

    CMake v3.13 or newer (you can install it using the Qt Online installer) x64

    使用Qt联机安装程序安装Qt for MCUs,该安装程序可通过Qt帐户下载

    安装Qt 5.14和Qt Creator 4.11 or higher

    安装链接

    › Qt: https://account.qt.io/downloads
    › CMake: https://cmake.org/download/
    › Python 2.7 32-bit: https://www.python.org/downloads/release/python-2716/
    › Arm GCC: https://developer.arm.com/tools-and-software/open-source-software/developer-tools/gnutoolchain/gnu-rm/downloads
    › J-Link Software Pack: https://www.segger.com/downloads/jlink/JLink_Windows.exe
    › J-Link OpenSDA Firmware: https://www.segger.com/downloads/jlink/OpenSDA_MIMXRT1050-EVKHyperflash
    › STM32CubeProgrammer: https://www.st.com/en/development-tools/stm32cubeprog.html
    › STM32 ST-LINK Utility: https://www.st.com/en/development-tools/stsw-link004.html​​​​​​​

    Qt Creator设置 启用Qt Creator插件 选择“帮助>关于插件”,然后从列表中选择“MCU支持(实验性)”插件,重新启动Qt Creator以应用更改
    替代文字 为MCU创建Qt工具包

    选择工具>选项>设备>MCU

    选择Qt for MCUs-Desktop 32bpp作为目标

    如果尚未设置,请提供Qt for MCUs安装目录的路径。

    单击Apply应用。

    替代文字

    替代文字
    替代文字

    注意:

    编译器要选X64,Qt版本要选64bit,CMake Tool选x64

    打开恒温器项目demo

    选择文件>打开文件或项目。。。

    打开CMakefiles.txt文件来自thermo文件夹的文件。

    选择Qt作为MCU-桌面32bpp套件。

    单击“配置项目”以完成。

    替代文字

    问题

    开发主机环境支持仅限于Windows 10

    C++编译失败,文本大字体.pixelSize.

    文本类型无法正确呈现需要复杂文本布局的unicode序列。对复杂文本使用StaticText

    read more
  • H

    hi 有问题请教你,方便加个联系方式吗

    read more
  • boost.asio是一个很棒的网络库,这回儿我也开始系统地学习起来了。想想当年接触boost,也有八年多了。这次开始接触boost,觉得既熟悉又陌生。熟悉的是小写字母+下划线的命名方式、晦涩的模板、很慢的编译速度以及较大的程序体积,陌生的是asio的各种概念:io服务、接收器、套接字等等:我之前对网络编程不是非常了解。

    于是根据我的理解,参考《Boost.Asio C++网络编程》实现了这样一个简单的客户端和服务端通信的例子,例子非常简单,还不完善,但是幸运的是,可以在本机上互通了。
    下面是客户端的代码:

    #include <iostream> #include <boost/asio.hpp> #include <boost/proto/detail/ignore_unused.hpp> using namespace std; using namespace boost::asio; using namespace boost::system; using namespace boost::proto::detail;// 提供ignore_unused方法 void writeHandler( const boost::system::error_code& ec, size_t bytesTransferred ) { if ( ec ) { cout << "Write data error, code: " << ec.value( ) << "transferred: " << bytesTransferred << endl; } else { cout << "OK! " << bytesTransferred << "bytes written. " << endl; } } int main(int argc, char *argv[]) { ignore_unused( argc ); ignore_unused( argv ); io_service service; ip::tcp::socket sock( service ); ip::tcp::endpoint ep( ip::address::from_string( "127.0.0.1" ), 6545 ); boost::system::error_code ec; sock.connect( ep, ec ); if ( ec ) { cout << "Connect error, code: " << ec.value( ) << ", We will exit." << endl; return ec.value( ); } else { char buf[1024] = "Hello world!"; sock.async_write_some( buffer( buf ), writeHandler ); sock.close( ); } return service.run( ); }

    下面是服务端的代码:

    #include <iostream> #include <boost/asio.hpp> #include <boost/proto/detail/ignore_unused.hpp> using namespace std; using namespace boost::asio; using namespace boost::system; using namespace boost::proto::detail;// 提供ignore_unused方法 void acceptHandle( const boost::system::error_code& code ) { cout << "Accepted." << endl; } int main(int argc, char *argv[]) { ignore_unused( argc ); ignore_unused( argv ); io_service service; ip::tcp::endpoint ep( ip::address::from_string( "127.0.0.1" ), 6545 ); boost::system::error_code ec; ip::tcp::socket sock( service ); ip::tcp::acceptor acceptor( service, ep ); acceptor.async_accept( sock, acceptHandle ); if ( ec ) { cout << "There is an error in server. code: " << ec.value( ) << endl; } return service.run( );// 阻塞运行 }

    运行结果是这样的:
    78448d7b-b3ae-42fc-9e2e-4dd2fbdac2c2-image.png

    我对boost.asio中几个概念的理解:

    io_service,这就是一个类似事件循环的东西,它为io设备提供服务,故名。不管是套接字、文件还是串口设备,都要使用它的服务。它的run()函数相当于启动了一个事件循环。一旦有消息了,即进行响应。这也是实现异步编程的重要基础。 socket,这个类则是套接字,可以处理TCP或者是UDP请求。有同步以及异步的处理方式,也有带异常以及不带异常的处理方式。 acceptor,接收器,仅仅是服务端使用。相当于其余框架中的listener,作接收用的。

    比较浅显,如果有不当之处,敬请指正。

    read more

关注我们

微博
QQ群