14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播

2023-11-20

1. UDP组播的特性

下图简单表示了组播的原理。UDP 组播是主机之间“一对一组”的通信模式,当多个客户端加入由一个组播地址定义的多播组之后,客户端向组播地址和端口发送的 UDP 数据报,组内成员都可以接收到,其功能类似于 QQ 群。

在这里插入图片描述

组播报文的目的地址使用 D 类 IP 地址,D 类地址不能出现在 IP 报文的源 IP 地址字段。用同一个 IP 多播地址接收多播数据报的所有主机构成了一个组,称为多播组 (或组播组)。所有的信息接收者都加入到一个组内,并且一旦加入之后,流向组地址的数据报立即开始向接收者传输,组中的所有成员都能接收到数据报。组中的成员是动态的,主机可以在任何时间加入和离开组。

所以,采用 UDP 组播必须使用一个组播地址。组播地址是 D 类IP 地址,有特定的地址段。多播组可以是永久的也可以是临时的。多播组地址中,有一部分由官方分配,称为永久多播组。永久多播组保持不变的是它的 IP 地址,组中的成员构成可以发生变化。永久多播组中成员的数量可以是任意的,甚至可以为零。那些没有保留下来的供永久多播组使用的 IP 组播地址,可以被临时多播组利用。关于组播IP 地址,有如下的一些约定:

  • 224.0.0.0~224.0.0.255 为预留的组播地址 (永久组地址),地址 224.0.0.0 保留不做分配,其他地址供路由协议使用;
  • 224.0.1.0~224.0.1.255 是公用组播地址,可以用于 Intermet;
  • 224.0.2.0~238.255.255.255 为用户可用的组播地址 (临时组地址),全网范围内有效;
  • 239.0.0.0~239.255.255.255 为本地管理组播地址,仅在特定的本地范围内有效。

所以,若是在家庭或办公室局域网内测试 UDP 组播功能,可以使用的组播地址范围是239.0.0.0~239.255.255.255。

QUdpSocket 支持 UDP 组播,joinMulticastGroup()函数使主机加入一个多播组,leaveMulticastGroup()函数使主机离开一个多播组,UDP 组播的特点是使用组播地址,其他的端口绑定、数据报收发等功能的实现与单播 UDP 完全相同。

2. UDP 组播实例程序的功能

设计一个UDP 组播实例程序 Samp14_4,在两台计算机上分别运行,进行组播通信。图 14-10是运行于主机 192.168.1.104 上的程序,图 14-11 是运行于主机 192.168.1.106 上的程序。两个主机上的程序都加入地址为239.255.43.21的多播组,绑定端口 35320进行通信。
从图 14-10 和图14-11可以看到,两个 Samp14_4 程序都可以发送和接收组播数据报,且在自已主机上发出的数据报,自己也可以接收到。

在这里插入图片描述

3. 组播功能的程序实现

程序的主窗口是基于 QMainWindow 的类 MainWindow,界面由 UI 设计器设计,其类定义如下(忽略 UI 设计器生成的槽函数):

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include    <QMainWindow>

#include    <QUdpSocket>
#include    <QLabel>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QLabel  *LabSocketState;
    QUdpSocket  *udpSocket;//用于与连接的客户端通讯的QTcpSocket
    QHostAddress    groupAddress;//组播地址
    QString getLocalIP();//获取本机IP地址
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void    onSocketStateChange(QAbstractSocket::SocketState socketState);
    void    onSocketReadyRead();//读取socket传入的数据
...

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

其中定义了一个QHostAddress 类型变量 groupAddress,用于记录组播地址。下面是 MainWindow的构造函数的代码:

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    LabSocketState=new QLabel("Socket状态:");//
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本地主机名
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);

    udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
//Multicast路由层次,1表示只在同一局域网内
    //组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1
    //默认值是1,表示数据包只能在本地的子网中传送。
    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
//    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,ui->spinTTL->value());

    connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(udpSocket->state());

    connect(udpSocket,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
}

其中使用了 QUdpSocket::setSocketOption()函数,对 socket 进行参数设置

udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);

将 socket 的 QAbstractSocket::MulticastTtlOption 值设置为1。MulticastTtlOption 是 UDP组播的数据报的生存期,数据报每跨1个路由会减1。缺省值为 1,表示多播数据报只能在同一路由下的局域网内传播。
要进行UDP 组播通信,UDP 客户端必须先加入UDP 多播组,也可以随时退出多播组。主窗口上的“加入组播”和“退出组播”按钮的代码如下:

void MainWindow::on_actStart_triggered()
{//加入组播
    QString     IP=ui->comboIP->currentText();
    groupAddress=QHostAddress(IP);//多播组地址
    quint16     groupPort=ui->spinPort->value();//端口

    if (udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress))//先绑定端口
    {
        udpSocket->joinMulticastGroup(groupAddress); //加入多播组
        ui->plainTextEdit->appendPlainText("**加入组播成功");
        ui->plainTextEdit->appendPlainText("**组播地址IP:"+IP);
        ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(groupPort));
        ui->actStart->setEnabled(false);
        ui->actStop->setEnabled(true);
        ui->comboIP->setEnabled(false);
    }
    else
        ui->plainTextEdit->appendPlainText("**绑定端口失败");
}

void MainWindow::on_actStop_triggered()
{//退出组播
    udpSocket->leaveMulticastGroup(groupAddress);//退出组播
    udpSocket->abort(); //解除绑定
    ui->actStart->setEnabled(true);
    ui->actStop->setEnabled(false);
    ui->comboIP->setEnabled(true);
    ui->plainTextEdit->appendPlainText("**已退出组播,解除端口绑定");
}

加入组播之前,必须先绑定端口,绑定端口的语句是:

udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress)

这里指定地址为QHostAddress::AnyIPv4,端口为多播组统一的一个端口。

使用 QUdpSocket:: joinMulticastGroup()函数加入多播组,即:

udpSocket->joinMulticastGroup(groupAddress); //加入多播组

多播组地址 groupAddress 由界面上的组合框里输入。注意,局域网内的组播地址的范围239.0.0.0~239.255.255.255,绝对不能使用本机地址作为组播地址。

退出多播组,使用 QUdpSocket::leaveMulticastGroup()函数,即:

udpSocket->leaveMulticastGroup(groupAddress);//退出组播

加入多播组后,发送组播数据报也是使用 writeDatagram()函数,只是目标地址使用的是组播地址,在 readyRead()信号的槽函数里用 readDatagram()读取数据报。下面是发送和读取数据报的代码:

void MainWindow::on_btnMulticast_clicked()
{//发送组播消息
    quint16     groupPort=ui->spinPort->value();
    QString  msg=ui->editMsg->text();
    QByteArray  datagram=msg.toUtf8();

    udpSocket->writeDatagram(datagram,groupAddress,groupPort);
//    udpSocket->writeDatagram(datagram.data(),datagram.size(),
//                     groupAddress,groupPort);
    ui->plainTextEdit->appendPlainText("[multicst] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();
}

void MainWindow::onSocketReadyRead()
{//读取数据报
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray   datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress    peerAddr;
        quint16 peerPort;
        udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);

//        udpSocket->readDatagram(datagram.data(),datagram.size());
        QString str=datagram.data();

        QString peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"] ";

        ui->plainTextEdit->appendPlainText(peer+str);
    }
}

4. 源码

4.1 可视化UI设计

在这里插入图片描述

4.2 mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include    <QMainWindow>

#include    <QUdpSocket>
#include    <QLabel>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

private:
    QLabel  *LabSocketState;
    QUdpSocket  *udpSocket;//用于与连接的客户端通讯的QTcpSocket
    QHostAddress    groupAddress;//组播地址
    QString getLocalIP();//获取本机IP地址
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void    onSocketStateChange(QAbstractSocket::SocketState socketState);
    void    onSocketReadyRead();//读取socket传入的数据
//
    void on_actStart_triggered();

    void on_actStop_triggered();

    void on_actClear_triggered();

    void on_actHostInfo_triggered();

    void on_btnMulticast_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

4.3 mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include    <QtNetwork>

QString MainWindow::getLocalIP()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);
    QString   localIP="";

    QList<QHostAddress> addList=hostInfo.addresses();//

    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            localIP=aHost.toString();
            break;
        }
    }
    return localIP;
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    LabSocketState=new QLabel("Socket状态:");//
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本地主机名
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);

    udpSocket=new QUdpSocket(this);//用于与连接的客户端通讯的QTcpSocket
//Multicast路由层次,1表示只在同一局域网内
    //组播TTL: 生存时间,每跨1个路由会减1,多播无法跨过大多数路由所以为1
    //默认值是1,表示数据包只能在本地的子网中传送。
    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);
//    udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,ui->spinTTL->value());

    connect(udpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(udpSocket->state());

    connect(udpSocket,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
}

MainWindow::~MainWindow()
{
    udpSocket->abort();
    delete udpSocket;
    delete ui;
}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;

    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;

    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;

    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;

    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void MainWindow::onSocketReadyRead()
{//读取数据报
    while(udpSocket->hasPendingDatagrams())
    {
        QByteArray   datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress    peerAddr;
        quint16 peerPort;
        udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddr,&peerPort);

//        udpSocket->readDatagram(datagram.data(),datagram.size());
        QString str=datagram.data();

        QString peer="[From "+peerAddr.toString()+":"+QString::number(peerPort)+"] ";

        ui->plainTextEdit->appendPlainText(peer+str);
    }
}

void MainWindow::on_actStart_triggered()
{//加入组播
    QString     IP=ui->comboIP->currentText();
    groupAddress=QHostAddress(IP);//多播组地址
    quint16     groupPort=ui->spinPort->value();//端口

    if (udpSocket->bind(QHostAddress::AnyIPv4, groupPort, QUdpSocket::ShareAddress))//先绑定端口
    {
        udpSocket->joinMulticastGroup(groupAddress); //加入多播组
        ui->plainTextEdit->appendPlainText("**加入组播成功");
        ui->plainTextEdit->appendPlainText("**组播地址IP:"+IP);
        ui->plainTextEdit->appendPlainText("**绑定端口:"+QString::number(groupPort));
        ui->actStart->setEnabled(false);
        ui->actStop->setEnabled(true);
        ui->comboIP->setEnabled(false);
    }
    else
        ui->plainTextEdit->appendPlainText("**绑定端口失败");
}

void MainWindow::on_actStop_triggered()
{//退出组播
    udpSocket->leaveMulticastGroup(groupAddress);//退出组播
    udpSocket->abort(); //解除绑定
    ui->actStart->setEnabled(true);
    ui->actStop->setEnabled(false);
    ui->comboIP->setEnabled(true);
    ui->plainTextEdit->appendPlainText("**已退出组播,解除端口绑定");
}

void MainWindow::on_actClear_triggered()
{
    ui->plainTextEdit->clear();
}

void MainWindow::on_actHostInfo_triggered()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");
    QHostInfo   hostInfo=QHostInfo::fromName(hostName);

    QList<QHostAddress> addList=hostInfo.addresses();//
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            QString IP=aHost.toString();
            ui->plainTextEdit->appendPlainText("本机IP地址:"+aHost.toString());
            if (ui->comboIP->findText(IP)<0)
                ui->comboIP->addItem(IP);
        }
    }
}


void MainWindow::on_btnMulticast_clicked()
{//发送组播消息
    quint16     groupPort=ui->spinPort->value();
    QString  msg=ui->editMsg->text();
    QByteArray  datagram=msg.toUtf8();

    udpSocket->writeDatagram(datagram,groupAddress,groupPort);
//    udpSocket->writeDatagram(datagram.data(),datagram.size(),
//                     groupAddress,groupPort);
    ui->plainTextEdit->appendPlainText("[multicst] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播 的相关文章

  • QCombobox 向下箭头图像

    如何更改Qcombobox向下箭头图像 现在我正在使用这个 QSS 代码 但这不起作用 我无法删除向下箭头边框 QComboBox border 0px QComboBox down arrow border 0px background
  • 在 C# 中按元素相乘数组具有意想不到的性能

    我想找到按元素相乘两个数组的最佳方法 这是更广泛项目的一部分 其中性能而不是唯一的考虑因素 我今天开始用 C Linqpad 编写一些函数 因此它还没有以任何方式进行优化 下面代码的输出如下 Environment ProcessorCou
  • 更改 Qt OpenGL 窗口示例以使用 OpenGL 3.3

    我正在尝试更改 Qt OpenGL 示例以使用更现代的 opengl 版本 330 似乎合适 所以我做了 在 main cpp 上设置版本和配置文件 设置着色器版本 更改着色器以使用统一 它现在构建没有任何错误 但我只看到一个空白窗口 我错
  • 如何在 C# / .NET 中创建内存泄漏[重复]

    这个问题在这里已经有答案了 可能的重复 托管代码中是否可能存在内存泄漏 特别是 C 3 0 https stackoverflow com questions 6436620 is it possible to have a memory
  • ASP.NET Web API 客户端 ProgressMessageHandler Post 任务卡在 WinForm 应用程序中

    我在用着HttpClient and ProgressMessageHandler来自MS ASP NET Web API 客户端库 http nuget org packages Microsoft AspNet WebApi Clien
  • 防止 boost::asio::io_context 在空轮询调用时停止

    此代码调用发布的句柄 boost asio io context ioc boost asio post ioc std cout lt lt lol lt lt std endl ioc poll 而这并没有 boost asio io
  • 类特定的新删除运算符是否必须声明为静态

    标准中是否要求类特定的 new new delete 和 delete 是静态的 我可以让它们成为非静态成员运算符吗 为什么需要它们是静态的 它们被隐式声明为静态 即使您没有键入 static
  • 与 Qt 项目的静态链接

    我有一个在 Visual Studio 2010 Professional 中构建的 Qt 项目 但是 当我运行它 在调试或发布模式下 时 它会要求一些 Qt dll 如果我提供 dll 并将它们放入 System32 中 它就可以工作 但
  • 为什么这个没有特殊字符的正则表达式会匹配更长的字符串?

    我正在使用此方法来尝试查找匹配项 例如 Regex Match A2 TS OIL TS OIL RegexOptions IgnoreCase Success 我得到了真实的结果 我很困惑 我认为这应该返回 false 因为模式中没有特殊
  • 时间:2019-03-17 标签:c#ThreadSafeDeepCopy

    我一直在阅读很多其他问题以及大量谷歌搜索 但我一直无法找到明确的解决方案 根据我读过的一些最佳实践 类的静态方法应该创建线程安全的 并且实例成员应该将线程安全留给消费者 我想为该类实现深度复制方法 该类本身还有其他引用类型成员 有没有什么方
  • 在 JSQMessagesViewController 中显示 LocationMediaItem

    我刚刚尝试实施LocationMediaItem in my Xamarin iOS应用程序使用JSQMessagesViewController 一切都很顺利 唯一的问题是UICollectionView应该显示位置的单元格永远停留在加载
  • C# 构建一个 webservice 方法,它接受 POST 方法,如 HttpWebRequest 方法

    我需要一个接受 POST 方法的 Web 服务 访问我的服务器正在使用 POST 方法 它向我发送了一个 xml 我应该用一些 xml 进行响应 另一方面 当我访问他时 我已经使用 HttpWebRequest 类进行了管理 并且工作正常
  • 将二进制数据从 C# 上传到 PHP

    我想将文件从 Windows C 应用程序上传到运行 PHP 的 Web 服务器 我知道 WebClient UploadFile 方法 但我希望能够分块上传文件 以便我可以监控进度并能够暂停 恢复 因此 我正在读取文件的一部分并使用 We
  • AES 输出是否小于输入?

    我想加密一个字符串并将其嵌入到 URL 中 因此我想确保加密的输出不大于输入 AES 是可行的方法吗 不可能创建任何始终会创建比输入更小的输出的算法 但可以将任何输出反转回输入 如果您允许 不大于输入 那么基本上您只是在谈论同构算法alwa
  • 无法在内存位置找到异常源:cudaError_enum

    我正在尝试确定 Microsoft C 异常的来源 test fft exe 中 0x770ab9bc 处的第一次机会异常 Microsoft C 异常 内存位置 0x016cf234 处的 cudaError enum 我的构建环境是 I
  • 运行选定的代码生成器时出错:“未将对象引用设置到对象的实例。”错误?

    我已经尝试了所有解决方案 例如修复 VS 2013 但没有用 当您通过右键单击控制器文件夹来创建控制器并添加控制器时 然后右键单击新创建的控制器的操作并选择添加视图 当我尝试创建视图时 就会发生这种情况 它不是一个新项目 而是一个现有项目
  • 是否有相当于 Clang/LLVM 的 .spec 文件,在哪里可以找到参考?

    The gcc驱动程序可以配置为使用特定的链接器 特定的选项和其他细节 例如覆盖系统头 specs files 当前 截至撰写本文时 GCC 版本 4 9 0 的手册此处描述了规范文件 https gcc gnu org onlinedoc
  • 新任务中使用的依赖注入服务

    我在需要时使用依赖项注入来访问我的服务 但我现在想要创建一个并发任务 但这会由于依赖项注入对象及其生命周期而导致问题 我读过这篇文章 标题 防止多线程 Link http mehdi me ambient dbcontext in ef6
  • 跨多个域的 ASP.NET 会话

    是否有合适的 NET 解决方案来在多个域上提供持久服务器会话 即 如果该网站的用户在 www site1 com 下登录 他们也将在 www site2 com 下登录 安全是我们正在开发的程序的一个问题 Thanks 它是否需要在会话中
  • Java 和/C++ 在多线程方面的差异

    我读过一些提示 多线程实现很大程度上取决于您正在使用的目标操作系统 操作系统最终提供了多线程能力 比如Linux有POSIX标准实现 而windows32有另一种方式 但我想知道编程语言水平的主要不同 C似乎为同步提供了更多选择 例如互斥锁

随机推荐

  • NBA球星莱昂纳德年纪以及成就

    莱昂约翰 德 莱昂纳德 LeBron James 现年35岁 是美国职业篮球运动员 曾三度获得NBA总冠军 六次获得常规赛最有价值球员奖 MVP 五次获得联盟最佳防守球员奖 和入选了十五次全明星阵容 是NBA史上最伟大的球员之一
  • lpv4dns服务器怎么修改,超简单方法让电脑网速飞起来,只需这么做:更改DNS服务器地址!...

    今天教大教一个技巧 让电脑浏览器打开网页速度更快 一般电脑默认是自动获取IP地址跟DNS服务器 我们手动更改为谷歌DNS 这样电脑浏览器打开网页的速度会快很多 1 鼠标右击任务栏本地连接图标 点击打开网络和共享中心 2 点击更改适配器设置
  • 计算机网络,用Excel画3种编码方式图(非归零编码,曼彻斯特编码,差分曼彻斯特编码)

    计算机网络 用Excel画3种编码方式图 非归零编码 曼彻斯特编码 差分曼彻斯特编码
  • Java及数据库事务

    数据库并发问题 1 脏读 读取未提交数据 A事务读取B事务尚未提交的数据 此时如果B事务发生错误并执行回滚操作 那么A事务读取到的数据就是脏数据 就好像原本的数据比较干净 纯粹 此时由于B事务更改了它 这个数据变得不再纯粹 这个时候A事务立
  • golang:环境变量GOPROXY和GO111MODULE设置

    我们安装完golang后 我们在windows的cmd命令下就可以直接查看和使用go命令和环境变量了 同样的在linux下可以在控制台使用 如下图所示 C Users lijie1 gt go env set GO111MODULE set
  • JUC并发编程共享模型之管程(三)(中)

    4 5Monitor概念 Java 对象头 以 32 位虚拟机为例 在32位虚拟机中 1个机器码等于4字节 也就是32bit 在64位虚拟机中 1个机器码是8个字节 也就是64bit 普通对象 数组对象 其中Mark Word 结构为 最后
  • A *a=new B();

    include
  • Anaconda 安装 Python 库(MySQLdb)的方法-(转)

    安装python库的过程中 最重要的地方就是版本需要兼容 其中操作系统为64位 Python为2 X 64位 下载安装文件的时候也要注意版本匹配 其中文件名中包含的cp27表示CPython 2 7版本 cp34表示CPython 3 4
  • 区块链项目 - 2 工作量证明

    2 1 ProofOfWork框架 我们在区块中添加一个属性Nonce来表示区块的生成难度 它是区块生成的一个重要条件 Nonce值越高 代表生成区块的难度越大 通过这种难度从而避免区块随意生成 工作量证明则是要完成这一系列难度区块生产所需
  • Qt 常用调试错误

    1 调试错误 问题 解决 可能是打开了两个Qt Creator 关闭一个 2 无法打开 debug sss exe 问题 解决 可能已经运行该程序 将其关闭 3 构建项目时发生错误 目标 桌面 问题 解决 点击左侧的项目 gt QT版本中选
  • 为什么在三线城市,Python工程师也能月薪20K?

    Python是这两年编程语言绝对的霸主 你可以发现 几乎所有和程序沾边的人 都在学Python 那么 Python到底有没有用 好在哪里 适合你学吗 今天就来详细分析一下 01 Python究竟能做什么 都说Python易学 究竟好学在哪里
  • Multitor:一款带有负载均衡功能的多Tor实例创建工具

    关于Multitor Multitor是一款带有负载均衡功能的多Tor实例创建工具 Multitor的主要目的是以最快的速度完成大量Tor进程的初始化 并将大量实例应用到我们日常使用的程序中 例如Web浏览器和聊天工具等等 除此之外 在该工
  • 如何做自动化测试

    这个话题比较大 相信大家也都有自己的想法 我在这里写一些我自己的看法 请大家指教 什么叫做自动化测试工程师 首先 会使用自动化测试工具的测试人员不能够称之为完全的自动化测试人员 这类测试人员被称为 工具小子 Script Kid 这个阶段还
  • 关于babel配置使用可选链

    什么是可选链 具体而言它是一种操作符 MDN给出的官方解释是 允许读取位于连接对象链深处的属性的值 而不必明确验证链中的每个引用是否有效 操作符的功能类似于 链式操作符 不同之处在于 在引用为空 nullish null 或者 undefi
  • 第4章 数据库应用系统功能设计与实施

    4 1软件体系结构与设计过程 4 1 1软件体系结构 软件体系结构又称软件架构 软件体系结构 构件 连接件 约束 其中 构件 Component 是组成系统的具有一定独立功能的不同粒度的程序模块 独立程序或软件子系统 是组成软件的系统元素
  • 关于jupyter notebook 更换环境的方法

    一 查看conda现有的环境 打开Anaconda Powershell Prompt 输入以下代码 conda env list 查看环境变量 可以看到如下已经配置的环境变量 二 激活现有环境 在Anaconda Powershell P
  • 使用react-markdown来解析markdown语法

    什么是 react markdown 组件 它是一个基于React的Markdown 编辑器组件 可以对代码进行高亮显示 链接 github网址 react markdown的安装 yarn add react markdown 引入 im
  • 链语BTChat力推“加密+社交” 引领区块链新社交时代

    近些年来互联网的发展日新月异 大数据化 人工智能 物联网这些都在成为人们生活中触手可及的东西 而区块链技能则被认为是继互联网之后最具颠覆性的创新技术 此前区块链技术在金融服务业 游戏 供应链等不同的产业中都有着广泛应用 同样的对于社交平台而
  • wsfuzzer video

    http www neurofuzz com modules software vidz php
  • 14-4_Qt 5.9 C++开发指南_QUdpSocket实现 UDP 通信_UDP组播

    文章目录 1 UDP组播的特性 2 UDP 组播实例程序的功能 3 组播功能的程序实现 4 源码 4 1 可视化UI设计 4 2 mainwindow h 4 3 mainwindow cpp 1 UDP组播的特性 下图简单表示了组播的原理