当前位置: 首页 > news >正文

QTcpSocket 服务端和客户端

前提:

pro文件中添加 QT += network

服务端主要采用信号槽机制,代码如如下

核心代码头文件#ifndef TCPSERVER_H
#define TCPSERVER_H#include <QObject>#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QMutex>
#include <QByteArray>
#include <QQueue>class OneSession{public:QTcpSocket* m_clientSocket;QByteArray m_buffer;QQueue<QByteArray> m_msgQueue;QString m_carName;int m_id;QString m_longitude;QString m_latitude;QString m_altitude;OneSession(){m_id = 0;}~OneSession(){}
};class CenterTcpSvr : public QTcpServer
{Q_OBJECT
public:CenterTcpSvr(QObject *parent = nullptr): QTcpServer(parent){}QList<OneSession> m_sessions;QMutex m_mutexForSessions;
protected:void incomingConnection(qintptr socketDescriptor) override;void readyReadFun();void clientDisconnectedFun();void printAllSessions();int parseHead(OneSession& _one);int parseCmdAndDeal(OneSession& _one);
};#endif // TCPSERVER_H核心代码源文件#include "centertcpsvr.h"void CenterTcpSvr::incomingConnection(qintptr socketDescriptor)
{QTcpSocket *socket = new QTcpSocket(this);if (!socket->setSocketDescriptor(socketDescriptor)) {qDebug() << "Error setting socket descriptor";socket->deleteLater();return;}{ //该括号配合锁使用,请不要随意删除,避免造成锁范围扩大QMutexLocker locker(&m_mutexForSessions); // 使用QMutexLocker自动管理互斥锁OneSession one;one.m_clientSocket = socket;m_sessions.append(one);printAllSessions();}// QTcpSocket::connectedconnect(socket, &QTcpSocket::readyRead, this, &CenterTcpSvr::readyReadFun);connect(socket, &QTcpSocket::disconnected, this, &CenterTcpSvr::clientDisconnectedFun);
}struct ProtocolHead{char flag[4];char version[4];char id[4]; //自己的IDchar cmd[4]; //1,注册;2,发给教辅;其他为车标号目标char bodySize[4];
};struct UserProtocolForward{char dst[4];
};int CenterTcpSvr::parseHead(OneSession& _one)
{int ret = -1;while (_one.m_buffer.size() > sizeof(ProtocolHead)) {char* tmpBuf = _one.m_buffer.data();if (_one.m_id == 0) {unsigned  id =     ((unsigned int)tmpBuf[8]  << 24 & 0xFF000000)+((unsigned int)tmpBuf[9]  << 16 & 0x00FF0000)+((unsigned int)tmpBuf[10] <<  8 & 0x0000FF00)+((unsigned int)tmpBuf[11]       & 0x000000FF);_one.m_id = id;}unsigned  bodySize = ((unsigned int)tmpBuf[16]  << 24 & 0xFF000000)+((unsigned int)tmpBuf[17]  << 16 & 0x00FF0000)+((unsigned int)tmpBuf[18] <<  8 & 0x0000FF00)+((unsigned int)tmpBuf[19]       & 0x000000FF);qDebug() << "bodySize is:" << bodySize;int outSize = sizeof(ProtocolHead) + bodySize;if (_one.m_buffer.size() >= outSize) {_one.m_msgQueue.enqueue(_one.m_buffer.left(outSize));_one.m_buffer.remove(0, outSize);ret = 0;} else {break;}}return  ret;
}int CenterTcpSvr::parseCmdAndDeal(OneSession& _one)
{int ret = 0;while (_one.m_msgQueue.size() > 0) {QByteArray bAarray = _one.m_msgQueue.dequeue();qDebug() << "dequeue content is:" << bAarray;char* tmpBuf = bAarray.data();unsigned  cmd =     ((unsigned int)tmpBuf[12]  << 24 & 0xFF000000)+((unsigned int)tmpBuf[13]  << 16 & 0x00FF0000)+((unsigned int)tmpBuf[14] <<  8 & 0x0000FF00)+((unsigned int)tmpBuf[15]       & 0x000000FF);if (cmd == 1){ //注册} else if (cmd == 2) { //发送给教辅} else {bool isIn = false;QList<OneSession>::iterator it;for(it = m_sessions.begin(); it != m_sessions.end(); ++it) {qDebug() << "cmd is : " << cmd  << "_one.m_id: " << _one.m_id ;if (cmd == it->m_id) { // 进到这里表示发送目标it->m_clientSocket->write(bAarray.data(), bAarray.size());it->m_clientSocket->waitForBytesWritten(1000);}}if (isIn) {ProtocolHead sendDataStruct;QByteArray sd;char body[] = {"{\"code\":0, \"msg\":OK}"};int bsize = sizeof(body);memcpy(sendDataStruct.flag, "#GD#", 4);memcpy(sendDataStruct.version, "0001", 4);sendDataStruct.bodySize[0] = 0 >> 24 & 0x000000FF;sendDataStruct.bodySize[1] = 0 >> 16 & 0x000000FF;sendDataStruct.bodySize[2] = 0 >> 8 & 0x000000FF;sendDataStruct.bodySize[3] = 0 & 0x000000FF;char* csend = new char[sizeof (ProtocolHead)+bsize];memset(csend, 0, sizeof(ProtocolHead) + bsize);memcpy(csend, (char*)(&sendDataStruct), sizeof(ProtocolHead));//_one.m_clientSocket->write(csend, sizeof(ProtocolHead) + bsize);_one.m_clientSocket->waitForBytesWritten(1000);delete []csend;}}}return ret;
}void CenterTcpSvr::readyReadFun() {QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender());//qDebug() << "readyReadData :" << clientSocket;QByteArray data = clientSocket->readAll();qDebug() << "data :" << data;QList<OneSession>::iterator it;for(it = m_sessions.begin(); it != m_sessions.end(); ++it) {if(clientSocket == it->m_clientSocket) {it->m_buffer.append(data);break;}}if (-1 == parseHead(*it)) { //解析头并分包放入队列return;}parseCmdAndDeal(*it);}void CenterTcpSvr::printAllSessions() { //此处没有上锁,请在上层使用处控制qDebug() << "clientDisconnectedFun begin. <-----------";QList<OneSession>::iterator it;for(it = m_sessions.begin(); it != m_sessions.end(); ++it) {qDebug() << "所有会话:::" << it->m_clientSocket;}qDebug() << "clientDisconnectedFun   end. ----------->";
}void CenterTcpSvr::clientDisconnectedFun() {QTcpSocket *clientSocket = qobject_cast<QTcpSocket*>(sender());qDebug() << "clientDisconnected :" << clientSocket;if (clientSocket) {// 移除断开连接的客户端socketQMutexLocker locker(&m_mutexForSessions); // 使用QMutexLocker自动管理互斥锁QList<OneSession>::iterator it;for(it = m_sessions.begin(); it != m_sessions.end(); ++it) {//qDebug() << "所有会话:" << clientSocket;if (it->m_clientSocket == clientSocket){clientSocket->deleteLater();m_sessions.erase(it);qDebug() << "删除会话:" << clientSocket;break;}}printAllSessions();}
}调用上述代码头文件#ifndef TEST_H
#define TEST_H#include <QObject>#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDebug>
#include <QThread>
#include <QString>
#include "centertcpsvr.h"class ThreadForCenterTcpSvr : public QThread
{Q_OBJECT
public:ThreadForCenterTcpSvr();void run(); //线程任务函数signals:void startsignal();  //启动⼦线程的信号
};#endif // TEST_H调用上述代码源文件#include "threadforcentertcpsvr.h"
#include <QCoreApplication>
#include "centertcpsvr.h"
#include <QByteArray>
#include <QCoreApplication>
#include <QNetworkAccessManager>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QUrl>
#include <QDebug>
#include <QThread>
#include <QString>ThreadForCenterTcpSvr::ThreadForCenterTcpSvr()
{}void ThreadForCenterTcpSvr::run()
{while (true){CenterTcpSvr* server = new CenterTcpSvr();if (!server->listen(QHostAddress::Any, 8080)) {qDebug() << "Server failed to start";return;}qDebug() << "Server start";QEventLoop loop;loop.exec(); // 进入事件循环,直到请求完成//QThread::exec(); //或者用这个也可以}
}在 main 函数中启动服务int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);ThreadForCenterTcpSvr* p = new ThreadForCenterTcpSvr();p->start();return a.exec();
}

客户端有两种实现方式

第一种方式如下,非信号槽方式实现

#include <QCoreApplication>#include <QTcpSocket>
#include <QThread>
#include <QByteArray>
#include <QAbstractSocket>struct ProtocolHead{char flag[4];char version[4];char id[4]; //自己的IDchar cmd[4]; //0,注册;1,发给教辅;其他为车标号目标char bodySize[4];
};int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);QTcpSocket socket;while (true) {// 连接到服务器socket.connectToHost("localhost", 8080);// 等待连接if(socket.waitForConnected(100000)) {qDebug() << "Connected!";int c = 0;while (true) {// 发送数据ProtocolHead sendDataStruct;QByteArray sd;char body[] = "Hello server!";int bsize = sizeof(body);memcpy(sendDataStruct.flag, "#GD#", 4);memcpy(sendDataStruct.version, "0001", 4);int id = 48102; //自己的标识sendDataStruct.id[0] = id >> 24 & 0x000000FF;sendDataStruct.id[1] = id >> 16 & 0x000000FF;sendDataStruct.id[2] = id >> 8 & 0x000000FF;sendDataStruct.id[3] = id & 0x000000FF;int cmd = 48102; //对方的标识sendDataStruct.cmd[0] = cmd >> 24 & 0x000000FF;sendDataStruct.cmd[1] = cmd >> 16 & 0x000000FF;sendDataStruct.cmd[2] = cmd >> 8 & 0x000000FF;sendDataStruct.cmd[3] = cmd & 0x000000FF;sendDataStruct.bodySize[0] = bsize >> 24 & 0x000000FF;sendDataStruct.bodySize[1] = bsize >> 16 & 0x000000FF;sendDataStruct.bodySize[2] = bsize >> 8 & 0x000000FF;sendDataStruct.bodySize[3] = bsize & 0x000000FF;char* csend = new char[sizeof (ProtocolHead)+bsize];memset(csend, 0, sizeof(ProtocolHead) + bsize);int pos = 0;memcpy(csend+pos, (char*)(&sendDataStruct), sizeof(ProtocolHead));pos += sizeof(ProtocolHead);memcpy(csend+pos, body, bsize);socket.write(csend, sizeof (ProtocolHead)+bsize);// 等待服务器响应if(socket.waitForBytesWritten(1000)){if (c%250000==0) {qDebug() << "Message sent!";}// 等待服务器的响应while(!socket.waitForReadyRead(1000)) {//QByteArray qb = socket.readAll();if (socket.error() == QAbstractSocket::SocketTimeoutError) {qDebug() << "超时错误:没有在指定时间内接收到数据";}if (socket.error() == QAbstractSocket::RemoteHostClosedError) {qDebug() << "远程主机关闭。";while (true) {//socket.abort();socket.connectToHost("localhost", 8080);// 等待连接if(socket.waitForConnected(1000)) {qDebug() << "Connected!";break;}}} else {qDebug() << "其他错误:" << socket.errorString();}}QByteArray qb = socket.readAll();qDebug() << c << ", ======Response received:" << qb;} else {qDebug() << "Failed to send message";}//break;c++;if (c/250000==10) {c=0;}}// 关闭连接socket.close();} else {qDebug() << "Failed to connect";}QThread::sleep(1);//break;}return a.exec();
}

第二种方式,信号槽方式

文件1#ifndef TCPCLIENT_H
#define TCPCLIENT_H#include <QObject>
#include <QTcpSocket>
#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QByteArray>
#include <QAbstractSocket>class TcpClient : public QObject
{Q_OBJECT
public:explicit TcpClient(QObject *parent = nullptr);~TcpClient();void connectToServer(const QString &host, quint16 port);private slots:void onConnected();void onDisconnected();void onReadyRead();void onBytesWritten(qint64 bytes);private:QTcpSocket *socket;
signals:};#endif // TCPCLIENT_H文件2#include "tcpclient.h"TcpClient::TcpClient(QObject *parent) : QObject(parent), socket(new QTcpSocket(this))
{connect(socket, &QTcpSocket::connected, this, &TcpClient::onConnected);connect(socket, &QTcpSocket::disconnected, this, &TcpClient::onDisconnected);connect(socket, &QTcpSocket::readyRead, this, &TcpClient::onReadyRead);connect(socket, &QTcpSocket::bytesWritten, this, &TcpClient::onBytesWritten);
}TcpClient::~TcpClient()
{delete socket; // Qt 自动管理内存,这里只是示例
}void TcpClient::connectToServer(const QString &host, quint16 port)
{socket->connectToHost(host, port);
}void TcpClient::onConnected()
{qDebug() << "Connected to server";socket->write("Hello, Server!");
}void TcpClient::onDisconnected()
{qDebug() << "Disconnected from server";
}void TcpClient::onReadyRead()
{while (socket->canReadLine()){QString line = socket->readLine().trimmed();qDebug() << "Received from server:" << line;}
}void TcpClient::onBytesWritten(qint64 bytes)
{qDebug() << "Sent" << bytes << "bytes to server";
}文件3#include <QCoreApplication>#include <QTcpSocket>
#include <QObject>
#include <QTcpSocket>
#include <QThread>
#include <QByteArray>
#include <QAbstractSocket>
#include "tcpclient.h"int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);TcpClient client;client.connectToServer("127.0.0.1", 8080); // 替换为实际的服务器 IP 和端口return a.exec();
}

相关文章:

QTcpSocket 服务端和客户端

前提&#xff1a; pro文件中添加 QT network 服务端主要采用信号槽机制&#xff0c;代码如如下 核心代码头文件#ifndef TCPSERVER_H #define TCPSERVER_H#include <QObject>#include <QTcpServer> #include <QTcpSocket> #include <QDebug> #inclu…...

Isaac Sim+SKRL机器人并行强化学习

目录 Isaac Sim介绍 OmniIssacGymEnvs安装 SKRL安装与测试 基于UR5的机械臂Reach强化学习测评 机器人控制 OMNI GYM环境编写 SKRL运行文件 训练结果与速度对比 结果分析 运行体验与建议 Isaac Sim介绍 Isaac Sim是英伟达出的一款机器人仿真平台&#xff0c;适用于做机…...

项目中用户数据获取遇到bug

项目跟练的时候 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘code’) at Proxy.userInfo (user.ts:57:17) 因此我想要用result接受信息的时候会出错&#xff0c;报错显示为result.code没有该值 导致我无法获取到相应的数据 解决如下 给…...

SpringSecurity+jwt+captcha登录认证授权总结

SpringSecurityjwtcaptcha登录认证授权总结 版本信息&#xff1a; springboot 3.2.0、springSecurity 6.2.0、mybatis-plus 3.5.5 认证授权思路和流程&#xff1a; 未携带token&#xff0c;访问登录接口&#xff1a; 1、用户登录携带账号密码 2、请求到达自定义Filter&am…...

项目技术栈-解决方案-web3去中心化

web3去中心化 Web3 DApp区块链:钱包:智能合约:UI:ETH系开发技能树DeFi应用 去中心化金融P2P 去中心化网络参考Web3 DApp 区块链: 以以太坊(Ethereum)为主流,也包括Solana、Aptos等其他非EVM链。 区块链本身是软件,需要运行在一系列节点上,这些节点组成P2P网络或者半…...

【AI声音克隆整合包及教程】第二代GPT-SoVITS V2:创新与应用

一、引言 随着科技的迅猛发展&#xff0c;声音克隆技术已经成为一个炙手可热的研究领域。SoVITS&#xff08;Sound Voice Intelligent Transfer System&#xff09;&#xff0c;作为该领域的先锋&#xff0c;凭借其卓越的性能和广泛的适用性&#xff0c;正在为多个行业带来前所…...

分清数据链路层、网络层、传输层的区别,以及这些层面的代表协议

目录 数据链路层 网络层 传输层 数据链路层 OSI模型的第二层&#xff0c;负责在相邻节点之间传输帧&#xff0c;处理帧的封装、地址、差错控制和流量控制等。确保数据在物理介质上可靠地传输&#xff0c;并为上层协议提供服务。 以太网&#xff08;Ethernet&#xff09;&…...

git没有识别出大写字母改成小写重命名的文件目录

Git 默认不会跟踪大写字母和小写字母的区别&#xff0c;因为在大多数文件系统中&#xff0c;大写字母和小写字母被认为是相同的文件&#xff0c;只有在区分大小写的文件系统中&#xff08;如 macOS 的 HFS 或 Windows 的 NTFS&#xff09;&#xff0c;这才是一个问题。 如果重命…...

自己动手写Qt Creator插件

文章目录 前言一、环境准备1.先看自己的Qt Creator IDE的版本2.下载源码 二、使用步骤1.参考原本的插件2.编写自定义插件1.cmakelist增加一个模块2.同理&#xff0c;qbs文件也增加一个3.插件源码 三、效果总结 前言 就目前而言&#xff0c;Qt Creator这个IDE&#xff0c;插件比…...

数据重塑:长宽数据转换【基于tidyr】

在数据分析和可视化过程中&#xff0c;数据的组织形式直接影响着我们能够进行的分析类型和可视化效果。这里简单介绍两种常见的数据格式&#xff1a;长格式&#xff08;Long Format&#xff09;和宽格式&#xff08;Wide Format&#xff09;&#xff0c;以及如何使用tidyr包进行…...

多模态大模型开启AI社交新纪元,Soul App创始人张璐团队亮相2024 GITEX GLOBAL

随着AI在全球范围内的加速发展和广泛应用,各行业纷纷在此领域发力。作为全球最大的科技盛会之一,2024年的GITEX GLOBAL将目光再次聚焦于人工智能的飞速发展,吸引了超过6700家来自各个领域的企业参与。在这样的背景下,Soul App作为国内较早将AI技术应用于社交领域的平台,首次亮相…...

实验6记录网络与故障排除

实验6记录网络与故障排除 实验目的及要求&#xff1a; 通过实验&#xff0c;掌握如何利用文档记录网络设备相关信息并完成网络拓扑结构的绘制。能够使用各种技术和工具来找出连通性问题&#xff0c;使用文档来指导故障排除工作&#xff0c;确定具体的网络问题&#xff0c;实施…...

QEMU 模拟器中运行的 Linux 系统

这两个文件通常用于在 QEMU 模拟器中运行的 Linux 系统&#xff0c;具体作用如下&#xff1a; 1. linux-aarch64-qemu.ext4&#xff1a; - **文件类型**&#xff1a;这是一个文件系统镜像文件&#xff0c;通常是 ext4 文件系统格式。 - **作用**&#xff1a;它包含了 Li…...

Ceph PG(归置组)的状态说明

Ceph PG&#xff08;Placement Group&#xff09;的状态反映了Ceph集群中数据的健康状况和分布情况。以下是Ceph PG的一些常见状态&#xff1a; Creating&#xff1a;创建状态。在创建存储池时&#xff0c;会创建指定数量的归置组&#xff08;PG&#xff09;。Ceph在创建一或多…...

Docker使用docker-compose一键部署nacos、Mysql、redis

下面是一个简单的例子&#xff0c;展示如何通过Docker Compose文件部署Nacos、MySQL和Redis。请确保您的机器上已经安装了Docker和Docker Compose。 1&#xff0c;准备好mysql、redis、nacos镜像 sudo docker pull mysql:8 && sudo docker pull redis:7.2 &&…...

HTTP常见的状态码有哪些,都代表什么意思

HTTP 协议定义了一系列的状态码&#xff0c;用于描述服务器对客户端请求的处理结果。这些状态码分为五个类别&#xff0c;每个类别都有特定的用途。 常见状态码 1开头 信息性状态码 这些状态码表示请求已被接收&#xff0c;继续处理。 100 Continue&#xff1a;客户端应继续…...

WebKit的Windows接口(适用2024年11月份版)

WebKit的Windows接口 使用cairo作为图形后端&#xff0c;libcurl作为网络后端。并且它只支持64位的Windows。 安装开发工具 安装带有“使用c进行桌面开发”工作负载的最新Visual Studio。 Activate Developer Mode.激活开发者模式。Build-webkit脚本创建一个指向生成的comp…...

Android 最新的AndroidStudio引入依赖失败如何解决?如:Failed to resolve:xxxx

错误信息&#xff1a; 在引入依赖时报错&#xff1a;Failed to resolve: xxx.xxxx:1.1.0 解决方案&#xff1a; 需要修改maven库的代理&#xff0c;否则就需要翻墙编译 新的AndroidStudio版本比较坑&#xff0c;修改代理的位置发生了变化&#xff1a; 最新变化&#xff1a;…...

ue5 蓝图学习(一)结构体的使用

在内容浏览器中右键 蓝图-选择结构体 下面这东西就是结构体&#xff0c;和C的结构体差不多 双击一下 可以添加变量&#xff0c;设置变量的类型和默认值。 可以在关卡蓝图中调用它。 点击打开关卡蓝图&#xff0c;添加变量 在变量的右侧&#xff0c;变量类型里搜索strcut&#…...

docker--工作目录迁移

前言 安装docker&#xff0c;默认的情况容器的默认存储路径会存储系统盘的 /var/lib/docker 目录下&#xff0c;系统盘一般默认 50G&#xff0c;容器输出的所有的日志&#xff0c;文件&#xff0c;镜像&#xff0c;都会存在这个地方&#xff0c;时间久了就会占满系统盘。 一、…...

网络六边形受到攻击

大家读完觉得有帮助记得关注和点赞&#xff01;&#xff01;&#xff01; 抽象 现代智能交通系统 &#xff08;ITS&#xff09; 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 &#xff08;…...

idea大量爆红问题解决

问题描述 在学习和工作中&#xff0c;idea是程序员不可缺少的一个工具&#xff0c;但是突然在有些时候就会出现大量爆红的问题&#xff0c;发现无法跳转&#xff0c;无论是关机重启或者是替换root都无法解决 就是如上所展示的问题&#xff0c;但是程序依然可以启动。 问题解决…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)

服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...

如何为服务器生成TLS证书

TLS&#xff08;Transport Layer Security&#xff09;证书是确保网络通信安全的重要手段&#xff0c;它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书&#xff0c;可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...

相机从app启动流程

一、流程框架图 二、具体流程分析 1、得到cameralist和对应的静态信息 目录如下: 重点代码分析: 启动相机前,先要通过getCameraIdList获取camera的个数以及id,然后可以通过getCameraCharacteristics获取对应id camera的capabilities(静态信息)进行一些openCamera前的…...

vue3 定时器-定义全局方法 vue+ts

1.创建ts文件 路径&#xff1a;src/utils/timer.ts 完整代码&#xff1a; import { onUnmounted } from vuetype TimerCallback (...args: any[]) > voidexport function useGlobalTimer() {const timers: Map<number, NodeJS.Timeout> new Map()// 创建定时器con…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

Selenium常用函数介绍

目录 一&#xff0c;元素定位 1.1 cssSeector 1.2 xpath 二&#xff0c;操作测试对象 三&#xff0c;窗口 3.1 案例 3.2 窗口切换 3.3 窗口大小 3.4 屏幕截图 3.5 关闭窗口 四&#xff0c;弹窗 五&#xff0c;等待 六&#xff0c;导航 七&#xff0c;文件上传 …...

Golang——7、包与接口详解

包与接口详解 1、Golang包详解1.1、Golang中包的定义和介绍1.2、Golang包管理工具go mod1.3、Golang中自定义包1.4、Golang中使用第三包1.5、init函数 2、接口详解2.1、接口的定义2.2、空接口2.3、类型断言2.4、结构体值接收者和指针接收者实现接口的区别2.5、一个结构体实现多…...