基于qt软件的网上聊天室软件

1.服务器:

        1).功能:

用于创建一个客户端,通过文本编辑器来获得端口号,根据获得的端口号创建服务器,等待客户端连接

创建成功会提示服务器创建成功

在收到客户端发送的信息时,把这条信息发送给其他所有客户端,实现群聊功能

        2).代码:

-------------------------------------------------------------------
.pro
-------------------------------------------------------------------
QT       += core gui networkgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \widget.cppHEADERS += \widget.hFORMS += \widget.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
-------------------------------------------------------------------
widget.h
-------------------------------------------------------------------
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>
#include <QMessageBox>
#include <QTcpServer>
#include <QTcpSocket>
#include <QPushButton>
#include <QLabel>
#include <QListWidget>
#include <QLineEdit>
#include <QList>QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACEclass Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();public slots:void connectbtn_slot();void connected_slot();void readyread_slot();private:Ui::Widget *ui;//定义服务器QTcpServer *server;//定义一个链表存放连接的客户端数据QList<QTcpSocket *> client;};
#endif // WIDGET_H
-------------------------------------------------------------------
main.cpp
-------------------------------------------------------------------
#include "widget.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}
-------------------------------------------------------------------
widget.cpp
-------------------------------------------------------------------
#include "widget.h"
#include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{ui->setupUi(this);//实例化服务器server = new QTcpServer(this);//连接按钮与对应槽函数connect(ui->connectbtn,&QPushButton::clicked,this,&Widget::connectbtn_slot);}Widget::~Widget()
{delete ui;
}//按下按钮后启动服务器
void Widget::connectbtn_slot()
{//读取端口号quint16 port = ui->portedit->text().toInt();//设置为监听状态if(!server->listen(QHostAddress::Any,port)){QMessageBox::critical(this,"失败","服务器启动失败");return ;}QMessageBox::information(this,"成功","服务器启动成功");//连接客户端信号与槽函数connect(server,&QTcpServer::newConnection,this,&Widget::connected_slot);
}//客户端连接槽函数
void Widget::connected_slot()
{//获取客户端套接字QTcpSocket *cli = server->nextPendingConnection();//将得到的套接字写入链表client.push_back(cli);//把新套接字与接收信号连接connect(cli,&QTcpSocket::readyRead,this,&Widget::readyread_slot);}//有信息写入准备读取
void Widget::readyread_slot()
{//删除已经断开的客户端for(int i = 0;i < client.size();i++){if(client.at(i)->state() == 0){client.removeAt(i);}}//遍历发送数据的客户端for(int i = 0;i < client.size();i++){if(client.at(i)->bytesAvailable() != 0){//读取客户端数据QByteArray msg = client.at(i)->readAll();//将数据写到ui界面中ui->listWidget->addItem(QString::fromLocal8Bit(msg));//将数据发送给所有客户端for(int j = 0;j < client.size();j++){client.at(j)->write(msg);}}}}

2.客户端:

登陆界面 :

        1).功能:

输入账号密码,如果点击注册按钮,会将输入的账号密码存入数据库中

且对输入的账号密码进行判断(没输入账号会提示请输入账号,没输入密码会提示请输入密码),输入的账号不能重复,但是密码可以重复;

如果点击登录按钮,会读取数据库中注册的账号密码,与输入的账号密码进行对比,

如果一致则提示登录成功并跳转到聊天室界面,如果在数据库中找不到账号则提示账号不存在,如果存在账号但是密码不正确,则输出密码错误

        2).代码:

-------------------------------------------------------------------
.pro
-------------------------------------------------------------------
QT       += core gui network sqlgreaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \chat.cpp \main.cpp \widget.cppHEADERS += \chat.h \widget.h# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += targetRESOURCES += \Icon.qrcFORMS += \chat.ui
-------------------------------------------------------------------
widget.h
-------------------------------------------------------------------
#ifndef WIDGET_H
#define WIDGET_H#include <QWidget>#include <QIcon>
#include <QLabel>
#include <QPushButton>
#include <QLineEdit>#include <QMessageBox>
#include <QDebug>#include <QSqlDatabase>
#include <QSqlQuery>class Widget : public QWidget
{Q_OBJECTpublic:Widget(QWidget *parent = nullptr);~Widget();signals:void loginsuccess_signal(QString account);public slots:void loginbtn_slot();void signinbtn_slot();private://组件QPushButton *login_btn;QPushButton *signin_btn;QLineEdit *account_edit;QLineEdit *pwd_edit;QLabel *main_lab;QLabel *account_lab;QLabel *pwd_lab;//数据库初始化QSqlDatabase db;};
#endif // WIDGET_H
-------------------------------------------------------------------
main.cpp
-------------------------------------------------------------------
#include "widget.h"
#include "chat.h"#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;chat c;w.show();QObject::connect(&w,&Widget::loginsuccess_signal,&c,&chat::openchatroom_slot);return a.exec();
}
-------------------------------------------------------------------
widget.cpp
-------------------------------------------------------------------
#include "widget.h"Widget::Widget(QWidget *parent): QWidget(parent)
{//---------------------------------窗口设置---------------------------------//设置窗口为固定大小this->setFixedSize(540,410);//设置窗口iconthis->setWindowIcon(QIcon(":/icon/wodepeizhenshi.png"));//设置窗口名this->setWindowTitle("鹏哥快聊");//---------------------------------标签设置---------------------------------//=====创建界面标签=====main_lab = new QLabel(this);//修改标签大小main_lab->resize(540,200);//在标签中插入图片main_lab->setPixmap(QPixmap(":/icon/logo.png"));//设置为自适应main_lab->setScaledContents(1);//=====创建账号标签=====account_lab = new QLabel(this);//修改标签大小account_lab->resize(50,40);//在标签中插入图片account_lab->setPixmap(QPixmap(":/icon/userName.jpg"));//移动到合适位置account_lab->move(90,220);//设置为自适应account_lab->setScaledContents(1);//=====创建密码标签=====pwd_lab = new QLabel(this);//修改标签大小pwd_lab->resize(account_lab->size());//在标签中插入图片pwd_lab->setPixmap(QPixmap(":/icon/passwd.jpg"));//移动到合适位置pwd_lab->move(account_lab->x(),account_lab->y()+80);//设置为自适应pwd_lab->setScaledContents(1);//---------------------------------按钮设置---------------------------------//=====创建登录按钮=====login_btn = new QPushButton(this);//设置按钮大小login_btn->resize(100,40);//在按钮上插入图片login_btn->setIcon(QIcon(":/icon/login.png"));//在按钮上输入文本login_btn->setText("登录");//移动到合适位置login_btn->move(270,360);connect(login_btn,&QPushButton::clicked,this,&Widget::loginbtn_slot);//=====创建注册按钮=====signin_btn = new QPushButton(this);//设置按钮大小signin_btn->resize(100,40);//在按钮上插入图片signin_btn->setIcon(QIcon(":/icon/cancel.png"));//在按钮上输入文本signin_btn->setText("注册");//移动到合适位置signin_btn->move(login_btn->x()+120,login_btn->y());connect(signin_btn,&QPushButton::clicked,this,&Widget::signinbtn_slot);//---------------------------------输入设置---------------------------------//=====创建账号输入=====account_edit = new QLineEdit(this);//设置占位文本account_edit->setPlaceholderText("QQ号码/手机/邮箱");//设置大小account_edit->resize(200,40);//移动到适合位置account_edit->move(account_lab->x()+100,account_lab->y());//=====创建密码输入=====pwd_edit = new QLineEdit(this);//设置占位文本pwd_edit->setPlaceholderText("密码");//设置大小pwd_edit->resize(account_edit->size());//移动到合适位置pwd_edit->move(pwd_lab->x()+100,pwd_lab->y());//设置回文显示模式pwd_edit->setEchoMode(QLineEdit::Password);//--------------------------------数据库设置--------------------------------//判断数据库是否存在if(!db.contains("user.db")){//不存在//创建一个数据库db = QSqlDatabase::addDatabase("QSQLITE");//命名为user.dbdb.setDatabaseName("user.db");}//存在//打开数据库if(!db.open()){//打开失败QMessageBox::critical(this,"error","数据库打开失败");return;}//打开成功//创建一个表//准备sql语句QString sql = "create table if not exists usertab(""account char primary key,""passwd char)";//创建一个数据库指令执行者QSqlQuery commend;//执行sql语句if(!commend.exec(sql)){//创建表失败QMessageBox::critical(this,"error","表格创建失败");return;}}Widget::~Widget()
{
}//登录按钮槽函数
void Widget::loginbtn_slot()
{//获取账号和密码QString account =  account_edit->text();QString passwd = pwd_edit->text();//从数据库中读取账号和密码QString sql = "select * from usertab";//创建执行者并执行sql语句QSqlQuery commend;if(!commend.exec(sql)){//查找失败QMessageBox::critical(this,"error","获取注册表失败");return;}//查找成功,循环比较数据库信息与输入的信息while (commend.next()){if(commend.value(0).toString() == account){//账号正确if(commend.value(1).toString() == passwd){QMessageBox::information(this,"success","登录成功");emit loginsuccess_signal(account);this->close();return;}//密码错误QMessageBox::critical(this,"failed","登录失败,密码错误");pwd_edit->clear();return;}}//账号错误QMessageBox::critical(this,"failed","登录失败,账号不存在");pwd_edit->clear();
}//注册按钮槽函数
void Widget::signinbtn_slot()
{//判断是否填写完整信息if(account_edit->text() == ""){QMessageBox::critical(this,"error","请输入账号");return;}if(pwd_edit->text() == ""){QMessageBox::critical(this,"error","请输入密码");return;}//获取界面上的账号和密码QString account = account_edit->text();QString passwd = pwd_edit->text();//将注册的账号密码写入数据库中//准备sql语句QString sql = QString("insert into usertab values(\"%1\",\"%2\")").arg(account).arg(passwd);//创建执行者并执行sql语句QSqlQuery commend;if(!commend.exec(sql)){//注册失败,账号重复QMessageBox::critical(this,"error","重复注册");return;}//注册成功QMessageBox::information(this,"success","注册成功");
}

聊天室界面:

        1).功能:

进入时,显示登录时的账号,且发送按钮、断开按钮和发送的文本编辑器不可用

通过主机的IP和端口号进行连接至主机后,给服务器发送xxx : 进入聊天室,发送按钮、断开按钮和发送的文本编辑器重新可用,使IP和端口号的文本编辑器以及连接聊天室按钮不可用

在发送的文本编辑器中写入信息并按下发送按钮后,会整合发送信息然后发送信息给服务器,发送后清空文本内容,

点击断开聊天室按钮,重新使发送按钮、断开按钮和发送的文本编辑器不可用,使IP和端口号的文本编辑器以及连接聊天室按钮可用

并会给服务器发送一条xxx : 离开聊天室的信息

        2).代码:

-------------------------------------------------------------------
chat.h
-------------------------------------------------------------------
#ifndef CHAT_H
#define CHAT_H#include <QWidget>
#include <QTcpSocket>
#include <QPushButton>
#include <QLabel>
#include <QLineEdit>
#include <QListWidget>
#include <QMessageBox>namespace Ui {
class chat;
}class chat : public QWidget
{Q_OBJECTpublic:explicit chat(QWidget *parent = nullptr);~chat();public slots:void openchatroom_slot(QString account);void connectbtn_slot();void connected_slot();void readyread_slot();void sndbtn_slot();void disconbtn_slot();void disconnect_slot();private:Ui::chat *ui;//定义一个客户端套接字QTcpSocket *client;//定义一个用户名QString username;};#endif // CHAT_H
-------------------------------------------------------------------
chat.cpp
-------------------------------------------------------------------
#include "chat.h"
#include "ui_chat.h"chat::chat(QWidget *parent) :QWidget(parent),ui(new Ui::chat)
{//将用户名居中显示//ui->usernamelab_2->setAlignment(Qt::AlignCenter);ui->setupUi(this);//为客户端套接字实例化空间client = new QTcpSocket(this);//连接按钮与对应槽函数连接connect(ui->connectbtn,&QPushButton::clicked,this,&chat::connectbtn_slot);//已连接信号与对应槽函数连接connect(client,&QTcpSocket::connected,this,&chat::connected_slot);//服务器发送信息信号与对应槽函数连接connect(client,&QTcpSocket::readyRead,this,&chat::readyread_slot);//发送按钮与对应槽函数连接connect(ui->sndbtn,&QPushButton::clicked,this,&chat::sndbtn_slot);//断开按钮与对应槽函数connect(ui->disconbtn,&QPushButton::clicked,this,&chat::disconbtn_slot);//断开连接信号与对应槽函数connect(client,&QTcpSocket::disconnected,this,&chat::disconnect_slot);//设置按钮与编辑框可用ui->disconbtn->setEnabled(0);ui->sndbtn->setEnabled(0);ui->msgedit->setEnabled(0);
}chat::~chat()
{delete ui;
}void chat::openchatroom_slot(QString account)
{username = account;qDebug() << account;qDebug() << username;ui->usernamelab_2->setText(username);this->show();
}//连接按钮槽函数
void chat::connectbtn_slot()
{//从ui界面读取IP与portQString IP = ui->IPedit->text();quint16 port = ui->portedit->text().toUInt();//连接服务器client->connectToHost(IP,port);
}//已连接槽函数
void chat::connected_slot()
{//连接完成提示信息QMessageBox::information(this,"成功","成功进入聊天室");//发送xx进入聊天室提示给服务器QString sndmsg = username + " : 进入聊天室";client->write(sndmsg.toLocal8Bit());//设置按钮与编辑框可用ui->IPedit->setEnabled(0);ui->portedit->setEnabled(0);ui->connectbtn->setEnabled(0);ui->sndbtn->setEnabled(1);ui->msgedit->setEnabled(1);ui->disconbtn->setEnabled(1);}//读取服务器发送信息
void chat::readyread_slot()
{//读取信息QByteArray msg = client->readAll();//将读取的信息发送到信息框内ui->listWidget->addItem(QString::fromLocal8Bit(msg));
}//发送按钮对应槽函数
void chat::sndbtn_slot()
{//读取ui界面发送框内信息QString msg = ui->msgedit->text();msg = username + " : " + msg;//将数据发送给服务器client->write(msg.toLocal8Bit());ui->msgedit->clear();
}//断开连接按钮对应槽函数
void chat::disconbtn_slot()
{//准备发送离开信息QString msg = username + " : 离开聊天室";client->write(msg.toLocal8Bit());//断开连接client->disconnectFromHost();
}//断开连接信号槽函数
void chat::disconnect_slot()
{QMessageBox::information(this,"断开连接","成功退出聊天室");//设置按钮与编辑框可用ui->IPedit->setEnabled(1);ui->portedit->setEnabled(1);ui->connectbtn->setEnabled(1);ui->disconbtn->setEnabled(0);ui->sndbtn->setEnabled(0);ui->msgedit->setEnabled(0);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/70748.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Linux-Day9-进程间通信】

进程间通信 前提引入&#xff1a; 我们之前接触过管道 | 将前一个命令的输出结果作为后一个命令的输入 如&#xff1a;ps | grep “sleep” 其实就是将 ps 的结果写入到一个区域&#xff0c;在从这个区域读出目标数据 有名管道 mkfifo 创建管道文件 : mkfifo fifo ->创…

单片机采集传感器数据(整形,浮点型)modbus上传

浮点型数据 占两个寄存器&#xff08;四个字节&#xff09; short 整形 占一个寄存器 &#xff08;两个字节&#xff09; 注意&#xff01;&#xff01;&#xff01;&#xff01; stm32 是小端模式&#xff0c;而modbus解析数据是大端模式 所以先发送高字节 如int a16777220…

selenium 自动化测试——环境搭建

安装python&#xff0c;并且使用pip命令安装 selenium pip3 install selenium 然后尝试第一次使用selenium 完成一个简单的测试自动化脚本 from selenium import webdriver from selenium.webdriver.common.by import By import timedriver webdriver.Chrome() driver.get(…

SAP MM学习笔记27- 购买依赖(采购申请)

前面已经努力的学习了 购买发注&#xff0c;入库&#xff0c;请求书照合 等功能&#xff0c;还是蛮多内容的哈。 剩下的功能&#xff0c;比如 右侧的 所要量决定&#xff0c;供给元决定&#xff0c;仕入先选择 还没学。 从这章开始&#xff0c;要开始学习它们了。 这一章先来…

儿童安全门和围栏,以及游戏围栏等美国站要求的合规标准是什么?

儿童安全门和围栏 儿童安全门和围栏用于在门口&#xff08;如门道&#xff09;内设置围栏&#xff0c;或用作自支撑围栏&#xff0c;将幼儿可能在其中活动的区域围起来。这些商品可能由塑料、金属、乙烯树脂或木制组件等材料制成。此政策包括但不限于可扩展围栏、伸缩安全门和…

初识Java 6-1 复用

目录 组合 继承 委托 组合和继承的结合 确保正确的清理 名称隐藏 在组合和继承之间选择 protected关键字 向上转型 final关键字 final数据 final方法 final类 初始化及类的重载 本笔记参考自&#xff1a; 《On Java 中文版》 对面向对象的编程语言而言&#xff0…

Windows系统管理一:操作系统概述

计算机系统的层次结构 五大基本功能 处理器管理 其工作主要是进程调度&#xff0c;在单用户单任务的情况下&#xff0c;必处理器仅为一个用户的一个任务所独占&#xff0c;进程管理的工作十分简单。但在多道程序或多用户的情况下&#xff0c;组织多个作业或任务时&#xff0c…

AJAX学习笔记8 跨域问题及解决方案

AJAX学习笔记7 AJAX实现省市联动_biubiubiu0706的博客-CSDN博客 跨域:指一个域名的网页去请求另外一个域名资源.比如百度页面去请求京东页面资源. 同源与不同源三要素:协议,域名,端口 协议一致,域名一致,端口一致.才算是同源.其他一律不同源 新建项目测试: 1.window.open();…

layui--记录

layui 行点击事件&#xff1a;点了没反应&#xff1f; //监听行工具事件layui.table.on(tool(demo), function (obj) {//alert(222) });原因&#xff1a;检查下id与lay-filter是否一致&#xff1b;id与lay-filter必须一致。 <table id"demo" lay-filter"dem…

Yarn资源调度器

文章目录 一、Yarn资源调度器1、架构2、Yarn工作机制3、HDFS、YARN、MR关系4、作业提交之HDFS&MapReduce 二、Yarn调度器和调度算法1、先进先出调度器&#xff08;FIFO&#xff09;2、容量调度器&#xff08;Capacity Scheduler&#xff09;3、公平调度器&#xff08;Fair …

pdf怎么转换成dwg格式?简单转换方法分享

当我们需要在CAD中编辑PDF文件中的向量图形时&#xff0c;将PDF转换成DWG格式是一个非常好的选择。因为PDF是一种非常流行的文档格式&#xff0c;很多时候我们会接收到PDF文件&#xff0c;但是PDF文件中的向量图形无法直接在CAD中编辑。而将PDF转换成DWG格式后&#xff0c;就可…

【网络层】网络基础 -- IP协议

引入IP协议头格式网段划分特殊的IP地址IP地址的数量限制 私有IP地址和公网IP地址分片与组装如何分片与组装&#xff1f; 引入 我们前面学习了传输层的相关知识&#xff0c;难道真的就是直接传送吗&#xff1f;当然不是&#xff0c;那TCP究竟做了什么&#xff1f;IP又扮演什么角…

图床项目详解

文章目录 一、图床项目介绍二、图床项目架构三、图床功能实现3.1 注册功能3.2 登录功能3.3 用户文件列表3.4 上传文件3.5 上传文件之秒传3.6 获取共享文件列表或下载榜3.7 分享/ 删除文件/ 更新下载数3.8 取消分享/ 转存/ 更新下载计数3.9 图床分享图片 一、图床项目介绍 实现…

想考PMP,符合报名条件么?怎么报考?

报考PMP第一步就是了解报名条件&#xff1a; PMP考试如何报名&#xff1f; 先在PMI官网报英文报名&#xff0c;再在人才交流基金会上报中文报名以及缴费。 1、英文报名 PMP英文报名就是在PMI网站上提交对应的英文材料信息。不限时间&#xff0c;随时可以报名&#xff0c;报…

2023年高教社杯 国赛数学建模思路 - 案例:最短时间生产计划安排

文章目录 0 赛题思路1 模型描述2 实例2.1 问题描述2.2 数学模型2.2.1 模型流程2.2.2 符号约定2.2.3 求解模型 2.3 相关代码2.4 模型求解结果 建模资料 0 赛题思路 &#xff08;赛题出来以后第一时间在CSDN分享&#xff09; https://blog.csdn.net/dc_sinor?typeblog 最短时…

leetcode645. 错误的集合(java)

错误的集合 题目描述优化空间代码演示 题目描述 难度 - 简单 LC645 - 错误的集合 集合 s 包含从 1 到 n 的整数。不幸的是&#xff0c;因为数据错误&#xff0c;导致集合里面某一个数字复制了成了集合里面的另外一个数字的值&#xff0c;导致集合 丢失了一个数字 并且 有一个数…

Talk | ICCV‘23南洋理工大学博士后李祥泰:面向统一高效的视频分割方法设计

本期为TechBeat人工智能社区第528期线上Talk&#xff01; 北京时间9月6日(周三)20:00&#xff0c;南洋理工大学博士后研究员—李祥泰的Talk已准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “面向统一高效的视频分割方法设计”&#xff0c;他分享了其在视…

华为云云服务器评测|安装Java8环境 配置环境变量 spring项目部署 【!】存在问题未解决

目录 引出安装JDK8环境查看是否有默认jar上传Linux版本的jar包解压压缩包配置环境变量 上传jar包以及运行问题上传Jar包运行控制台开放端口访问失败—见问题记录关闭Jar的方式1.进程kill -92.ctrl c退出 问题记录&#xff1a;【!】未解决各种方式查看端口情况联系工程师最后排查…

在Ubuntu Linux系统上安装RabbitMQ服务并解决公网远程访问问题

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…

智能电销机器人,主要体现的价值是什么

21世纪科技的迅速发展&#xff0c;人工智能逐渐走入大家的视线&#xff0c;越来越多的机器人出现在我们生活中。见的最多的有电销公司的智能语音机器人、在仓库拣货打包的机器人、商场店铺供娱乐对话的机器人。机器人活跃在各行各业中&#xff0c;降低了人工成本&#xff0c;代…