环境:Win7x64、Qt5.3.2 MSVC OpenGL(x86)、vs2010(x86)

ZC:这里的例子是 同步的函数操作,貌似 如果子线程在等待 WaitCommEvent(...)或ReadFile(...) 返回的话(即 串口句柄正在被使用中),界面主线程执行 CloseHandle(...) 或 SetCommMask(...) 的话,就会卡在那里...    于是 考虑改用 异步方式

  ZC:想到 一个方式,使用同步方式的时候 可以使用 强制关闭线程的方式“TerminateThread(线程句柄, ExitCode);” 来关闭子线程,这样就不会再占用 串口句柄了,CloseHandle(..)也可以顺利执行。问题:TerminateThread(...) 会有一些 动态申请的资源释放,获取的锁释放 等的问题(具体看MSDN的说明,里面还提到了"heap lock",于是在 申请内存的过程中 如果强制结束线程的话 堆锁未释放 别的线程再申请内存的时候就卡在那里了...),还有 在 XP以及之前的Windws版本OS中 强制结束线程 OS不会释放 它的初始栈,造成内存泄漏(我看了一下 XP的资源管理器,确实是这样的现象)。

1、ZC:

 1.1、开始时,遇到的问题:在接收信息的线程中,ReadFile(...) 每次都是 立即返回的  但是获取的数据都是0字节的长度,现象就好像是 用了 异步的方式 没等到事件 就立即返回了...

  找到问题:(1)、查看了 CreateFile(...)的参数,发现使用的就是 同步的方式(没有指定 参数 FILE_FLAG_OVERLAPPED)

       (2)、后来 发现是 COMMTIMEOUTS 设置的不正确的缘故

  测试下来,有2种方式 设置COMMTIMEOUTS,来 解决上面的问题:

    ①、类似如下的参数设置:

         COMMTIMEOUTS TimeOuts;
//设定读超时
TimeOuts.ReadIntervalTimeout = 100;
TimeOuts.ReadTotalTimeoutMultiplier = 5000;
TimeOuts.ReadTotalTimeoutConstant = 5000;
//设定写超时
TimeOuts.WriteTotalTimeoutMultiplier = 500;
TimeOuts.WriteTotalTimeoutConstant = 2000;

    ②、这样设置:

         COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts(hCom1, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = ;
CommTimeOuts.ReadTotalTimeoutConstant = ;
CommTimeOuts.WriteTotalTimeoutMultiplier = ;
CommTimeOuts.WriteTotalTimeoutConstant = ;

      ZC:光是这样设置的话,就会出现上面的问题,ReadFile(...) 立即返回 0字节数据。接收线程 就会 连续不断的去ReadFile(...) ...

      ZC:这样设置的话,需要 使用 “SetCommMask(hCom1, EV_RXCHAR);” 和 “DWORD dwMask = EV_RXFLAG; WaitCommEvent(g_hCom, &dwMask, NULL);”,使用 它们 就是 声明和等待EV_RXCHAR事件(该事件 意思是 只要输入缓冲区接收到数据就会触发)

      

2、测试代码:

  2,1、main.cpp

#include "MainWindow.h"
#include <QApplication> extern MainWindow* g_pMainWindow; int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show(); g_pMainWindow = &w;
a.installNativeEventFilter(&w);// 注意,不是“a.installEventFilter(w);”,少了 "Native" return a.exec();
}

  2.2、MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H #include <QMainWindow>
#include <QAbstractNativeEventFilter> namespace Ui {
class MainWindow;
} class MainWindow : public QMainWindow, public QAbstractNativeEventFilter
{
Q_OBJECT public:
explicit MainWindow(QWidget *parent = );
~MainWindow(); public:
virtual bool nativeEventFilter(const QByteArray &eventType, void *message, long *); private slots:
void on_pbtnConn_clicked();
void on_pbtnRecvMsgClear_clicked();
void on_pbtnSendMsgClear_clicked();
void on_pbrnSend_clicked(); public:
Ui::MainWindow *ui;
}; #endif // MAINWINDOW_H

  2.3、MainWindow.cpp

#include "MainWindow.h"
#include "ui_MainWindow.h" MainWindow* g_pMainWindow = NULL; MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this); // https://blog.csdn.net/horizons_kong/article/details/54412339
// https://blog.csdn.net/zmdsjtu/article/details/78539681
} MainWindow::~MainWindow()
{
delete ui;
} #include <QDebug>
#include <windows.h>
#include <stdio.h>
#include <process.h> #include "thread_z.h"
#include "PassInfo_z.h"
#include "SeriesPort_z.h" QString TimeNowZ()
{
SYSTEMTIME sys;
GetLocalTime( &sys ); char buf[] = {};
sprintf_s( buf, sizeof(buf), "%02d:%02d:%02d.%03d ", sys.wHour, sys.wMinute, sys.wSecond, sys.wMilliseconds ); return QString::fromLocal8Bit(buf);
} void ShowMsgZ(const QString& _str)
{
if (g_pMainWindow != NULL)
g_pMainWindow->ui->teRecv->append(_str);
} bool MainWindow::nativeEventFilter(const QByteArray &eventType, void *message, long *)
{
MSG* pMsg = reinterpret_cast<MSG*>(message);
if(pMsg->message == WM_PASSINFO)
{
int iLen = pMsg->wParam;
QString strInfo = Info_Recv(ShowMsgZ, iLen, (char*)pMsg->lParam);
if (! strInfo.isNull())
//ui->teRecv->append(TimeNowZ() + strInfo);
ui->teRecv->append(strInfo);
else
ui->teRecv->append("\r\n"); return true;
} return false;
} void MainWindow::on_pbtnConn_clicked()
{
QString strChuanKouHao = ui->cbChuanKouHao->currentText();
QString strBoTeLv = ui->cbBoTeLv->currentText();
BYTE Parity = (BYTE)ui->cbJiaoYanWei->currentIndex();
BYTE ShuJuWei = (BYTE)(ui->cbShuJuWei->currentIndex() + );
BYTE TingZhiWei = ((BYTE)ui->cbTingZhiWei->currentIndex() + ) * 0.5;
bool bRtn = SPort_Init(ShowMsgZ, strChuanKouHao.toLocal8Bit().data(),
strBoTeLv.toULong(), Parity, ShuJuWei, TingZhiWei);
if (! bRtn)
{
ui->pbtnConn->setChecked(false);
return;
} ShowMsgZ("After SPort_Init(...)");
_beginthread(Thread_RECV, , (void*)this->winId());
ShowMsgZ("After _beginthread(...)");
} void MainWindow::on_pbtnRecvMsgClear_clicked()
{
ui->teRecv->clear();
//_beginthread(Thread_RECV, 0, (void*)this->winId());
} void MainWindow::on_pbtnSendMsgClear_clicked()
{
ui->teSend->clear();
} void MainWindow::on_pbrnSend_clicked()
{
// char pc[] = {128,129};
// if (IsDBCSLeadByte(pc[0]))
// qDebug() << "T";
// else
// qDebug() << "F"; ui->teRecv->append("\r\n");
}

  2.4、PassInfo_z.h

#ifndef PASSINFO_Z_H
#define PASSINFO_Z_H #include <QString> #include <Windows.h>
#define WM_PASSINFO WM_USER+0x1000 typedef void (__cdecl *TshowMsg)(const QString& _str); void Info_Send(HWND _hWnd, int _iLen, char* _pc);
void Info_Send_pc(HWND _hWnd, char* _pc);
QString Info_Recv(TshowMsg _funcShowMsg, int _iLen, char* _pc); #endif // PASSINFO_Z_H

  2.5、PassInfo_z.cpp

#include "PassInfo_z.h"

void Info_Send(HWND _hWnd, int _iLen, char* _pc)
{
if (_hWnd == )
return; if (_iLen > )
{
char* pc = new char[_iLen];
memcpy(&pc[], _pc, _iLen); PostMessage( _hWnd, WM_PASSINFO, WPARAM(_iLen), LPARAM(pc) );
}
else
PostMessage( _hWnd, WM_PASSINFO, WPARAM(_iLen), );
} void Info_Send_pc(HWND _hWnd, char* _pc)
{
Info_Send(_hWnd, strlen(_pc), _pc);
} QString Info_Recv(TshowMsg _funcShowMsg, int _iLen, char* _pc)
{
// ZC: 进入到这个函数,前提是 "_iLen > 0"
if (_iLen <= )
return QString::null;
return QString::fromLocal8Bit(_pc, _iLen);
} // ZC: IsDBCSLeadByte( char ):BOOL; // ZC: 判断是否是 中文/韩文等字符的第1个字节
//char g_infoRecv[1024 * 4] = {0};
//int g_iInfoRecvCnt = 0; //QString Info_Recv(TshowMsg _funcShowMsg, int _iLen, char* _pc)
//{
// // ZC: 进入到这个函数,前提是 "_iLen > 0" // _funcShowMsg(QString::number(g_iInfoRecvCnt)); // if (g_iInfoRecvCnt > 0)
// {
// memcpy(&g_infoRecv[g_iInfoRecvCnt], _pc, _iLen);
// g_iInfoRecvCnt += _iLen; // if (! IsDBCSLeadByte(_pc[_iLen - 1]) )// ZC: 判断是否是 中文/韩文等字符的第1个字节
// {
// QString str = QString::fromLocal8Bit(g_infoRecv, g_iInfoRecvCnt);
// g_iInfoRecvCnt = 0;
// return str;
// }
// }
// else
// {
// if ( IsDBCSLeadByte(_pc[_iLen - 1]) )
// {
// memcpy(&g_infoRecv[g_iInfoRecvCnt], _pc, _iLen);
// g_iInfoRecvCnt += _iLen;
// }
// else
// return QString::fromLocal8Bit(_pc, _iLen);
// }
// return QString::null;
//}

  2.6、SeriesPort_z.h

#ifndef SERIESPORT_Z_H
#define SERIESPORT_Z_H #include <Windows.h>
#include <QString> extern HANDLE g_hCom; #define SERIES_PORT__IN_QUEUE_SIZE 1024 * 16
#define SERIES_PORT__OUT_QUEUE_SIZE 1024 * 16 typedef void (__cdecl *TshowMsg)(const QString& _str); bool SPort_Init(TshowMsg _funcShowMsg,
char* _pcSeriesPortName, DWORD _BaudRate, BYTE _Parity, BYTE _ByteSize, BYTE _StopBits); #endif // SERIESPORT_Z_H

  2.7、SeriesPort_z.cpp

#include "SeriesPort_z.h"

#include <QDebug>
#include <QTextCodec> #include "PassInfo_z.h" //HWND g_hWnd = 0;
HANDLE g_hCom = ; bool SPort_Init(TshowMsg _funcShowMsg,
char* _pcSeriesPortName,
DWORD _BaudRate, BYTE _Parity, BYTE _ByteSize, BYTE _StopBits)
{
g_hCom = ; WCHAR wszSeriesPortName[] = {};
MultiByteToWideChar(CP_ACP, , _pcSeriesPortName, strlen(_pcSeriesPortName) + ,
wszSeriesPortName, sizeof(wszSeriesPortName) / sizeof(wszSeriesPortName[]));
HANDLE hCom1 = CreateFile(wszSeriesPortName,//COM1口
GENERIC_READ | GENERIC_WRITE, //允许读和写
, //独占方式
NULL,
OPEN_EXISTING, //打开而不是创建
, //同步方式
NULL);
if (hCom1 == INVALID_HANDLE_VALUE)
{
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("打开COM失败 !");
_funcShowMsg(strPrint);
return false;
}
else
{
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("COM打开成功 !");
_funcShowMsg(strPrint);
} // SetupComm(hCom1, SERIES_PORT__IN_QUEUE_SIZE, SERIES_PORT__OUT_QUEUE_SIZE); //输入缓冲区和输出缓冲区的大小都是1024 // COMMTIMEOUTS TimeOuts;
// //设定读超时
// TimeOuts.ReadIntervalTimeout = 100;
// TimeOuts.ReadTotalTimeoutMultiplier = 5000;
// TimeOuts.ReadTotalTimeoutConstant = 5000;
// //设定写超时
// TimeOuts.WriteTotalTimeoutMultiplier = 500;
// TimeOuts.WriteTotalTimeoutConstant = 2000;
// if (! SetCommTimeouts(hCom1, &TimeOuts)) //设置超时
// {
// int iErr = ::GetLastError();
// QTextCodec *pCodec = QTextCodec::codecForName("GBK");
// QString strPrint = pCodec->toUnicode("设置串口读写超时时间失败");
// strPrint += ", last error code is "+QString::number(iErr);
// _funcShowMsg(strPrint);
// return false;
// } // DCB dcb;
// GetCommState(hCom1, &dcb);
// dcb.BaudRate = _BaudRate;//9600; //波特率为9600
// dcb.ByteSize = _ByteSize;//8; //每个字节有8位
// dcb.Parity = _Parity;//NOPARITY; //无奇偶校验位
// dcb.StopBits = _StopBits;//ONESTOPBIT; //1个停止位
// if (! SetCommState(hCom1, &dcb))
// {
// int iErr = ::GetLastError();
// QTextCodec *pCodec = QTextCodec::codecForName("GBK");
// QString strPrint = pCodec->toUnicode("设置串口参数失败");
// strPrint += ", last error code is "+QString::number(iErr);
// _funcShowMsg(strPrint);
// return false;
// } _funcShowMsg( QString::number(_BaudRate)+","+QString::number(_ByteSize)
+","+QString::number(_Parity)+","+QString::number(_StopBits) ); DCB dcb;
if (! GetCommState(hCom1, &dcb))
{
int iErr = ::GetLastError();
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("获取串口当前属性参数失败");
strPrint += ", last error code is "+QString::number(iErr);
_funcShowMsg(strPrint);
return false;
}
//配置串口参数
dcb.BaudRate = _BaudRate; //波特率
dcb.fBinary = TRUE; //二进制模式。必须为TRUE
dcb.ByteSize = _ByteSize; //数据位。范围4-8
dcb.StopBits = _StopBits; //停止位
if (_Parity == NOPARITY)
{
dcb.fParity = FALSE; //奇偶校验。无奇偶校验
dcb.Parity = _Parity; //校验模式。无奇偶校验
}
else
{
dcb.fParity = TRUE; //奇偶校验。
dcb.Parity = _Parity; //校验模式。无奇偶校验
}
dcb.fOutxCtsFlow = FALSE; //CTS线上的硬件握手
dcb.fOutxDsrFlow = FALSE; //DST线上的硬件握手
dcb.fDtrControl = DTR_CONTROL_ENABLE;//DTR控制
dcb.fDsrSensitivity = FALSE;
dcb.fTXContinueOnXoff = FALSE;//
dcb.fOutX = FALSE; //是否使用XON/XOFF协议
dcb.fInX = FALSE; //是否使用XON/XOFF协议
dcb.fErrorChar = FALSE; //是否使用发送错误协议
dcb.fNull = FALSE; //停用null stripping
dcb.fRtsControl = RTS_CONTROL_ENABLE;//
dcb.fAbortOnError = FALSE; //串口发送错误,并不终止串口读写
//设置串口参数
if (! SetCommState(hCom1, &dcb))
{
int iErr = ::GetLastError();
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("设置串口参数失败");
strPrint += ", last error code is "+QString::number(iErr);
_funcShowMsg(strPrint);
return false;
} //设置串口事件
SetCommMask(hCom1, EV_RXCHAR);//在缓存中有字符时产生事件 SetupComm(hCom1, SERIES_PORT__IN_QUEUE_SIZE, SERIES_PORT__OUT_QUEUE_SIZE); //设置串口读写时间
COMMTIMEOUTS CommTimeOuts;
GetCommTimeouts(hCom1, &CommTimeOuts);
CommTimeOuts.ReadIntervalTimeout = MAXDWORD;
CommTimeOuts.ReadTotalTimeoutMultiplier = ;
CommTimeOuts.ReadTotalTimeoutConstant = ;
CommTimeOuts.WriteTotalTimeoutMultiplier = ;
CommTimeOuts.WriteTotalTimeoutConstant = ;
if (!SetCommTimeouts(hCom1, &CommTimeOuts))
{
int iErr = ::GetLastError();
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("设置串口读写超时时间失败");
strPrint += ", last error code is "+QString::number(iErr);
_funcShowMsg(strPrint);
return false;
} g_hCom = hCom1;
return true;
} bool SendData(TshowMsg _funcShowMsg, HANDLE _hComm, char* data, int len)
{
if (_hComm == INVALID_HANDLE_VALUE)
{
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("串口未打开");
_funcShowMsg(strPrint);
return false;
}
//清空串口
PurgeComm(_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);
//写串口
DWORD dwWrite = ;
DWORD dwRet = WriteFile(_hComm, data, len, &dwWrite, NULL);
int iErr = ;
if (! dwRet) { iErr = ::GetLastError(); }
//清空串口
PurgeComm(_hComm, PURGE_RXCLEAR | PURGE_TXCLEAR);
if (! dwRet)
{
QTextCodec *pCodec = QTextCodec::codecForName("GBK");
QString strPrint = pCodec->toUnicode("发送数据失败");
strPrint += ", last error code is "+QString::number(iErr);
_funcShowMsg(strPrint);
return false;
}
return true;
}

  2.8、thread_z.h

#ifndef THREAD_Z_H
#define THREAD_Z_H void Thread_RECV(void *_ArgList); #endif // THREAD_Z_H

  2.9、thread_z.cpp

#include "thread_z.h"

#include <QDebug>

#include <Windows.h>
#include <process.h> #include "PassInfo_z.h"
#include "SeriesPort_z.h" int g_iIdx = ;
bool MsgHandler01(HWND _hWnd, DWORD _dwRecv, char* _pc); void Thread_RECV(void *_ArgList)
{
// ::MessageBoxA(0, "Thread_RECV(...) in ", "", 0); HWND hWnd = (HWND)_ArgList;
if (hWnd == )
{
qDebug() << "Thread_RECV(...) - hWnd is NULL .";
_endthread();
return;
}
if (g_hCom == )
{
Info_Send_pc(hWnd, "Thread_RECV(...) - g_hCom is 0 .");
_endthread();
return;
} Info_Send_pc(hWnd, "Thread_RECV(...) in");
qDebug() << "Thread_RECV(...) in"; //清空串口
PurgeComm(g_hCom, PURGE_RXCLEAR | PURGE_TXCLEAR); char buf[SERIES_PORT__OUT_QUEUE_SIZE] = {};
char bufErr[] = {};
while (true)
{
// g_iIdx ++;
// if (g_iIdx > 10)
// break; BOOL bRtn = false; DWORD dwMask = EV_RXFLAG;//EV_RXCHAR;
bRtn = WaitCommEvent(g_hCom, &dwMask, NULL);
if (! bRtn)
{
int iErr = ::GetLastError();
sprintf_s(bufErr, sizeof(bufErr), "WaitCommEvent(...) return false, last error code is %d .", iErr);
Info_Send_pc(hWnd, bufErr);
break;
} DWORD dwRead;
bRtn = ReadFile(g_hCom, &buf[], SERIES_PORT__OUT_QUEUE_SIZE, &dwRead, NULL);
// {
// char msg[128] = {0};
// sprintf_s(msg, sizeof(msg), "%d - %d", g_iIdx, dwRead);
// Info_Send_pc(hWnd, msg);
// }
if (! bRtn)
{
int iErr = ::GetLastError();
sprintf_s(bufErr, sizeof(bufErr), "ReadFile(...) return false, last error code is %d .", iErr);
Info_Send_pc(hWnd, bufErr);
break;
} if (dwRead > )
if (! MsgHandler01(hWnd, dwRead, buf))
break;
} Info_Send_pc(hWnd, "Thread_RECV(...) out");
qDebug() << "Thread_RECV(...) out"; /* _endthread given to terminate */
_endthread();
} // *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** char g_infoRecv[ * ] = {};
DWORD g_dwInfoRecvCnt = ; bool MsgHandler01(HWND _hWnd, DWORD _dwRecv, char* _pc)
{
//char buf1[64] = {0}; memcpy(&g_infoRecv[g_dwInfoRecvCnt], _pc, _dwRecv);
g_dwInfoRecvCnt += _dwRecv; //Info_Send_pc(_hWnd, "11");
void* p = memchr(&g_infoRecv[], '\n', g_dwInfoRecvCnt);
if (p != NULL)
{
//Info_Send_pc(_hWnd, "12");
DWORD dwBegin = (DWORD)( &g_infoRecv[] );
DWORD dwPos = (DWORD)p;
int iLen = dwPos - dwBegin - ;// \r\n 为占2个字节位置,需要将它们占的位置去掉
//Info_Send_pc(_hWnd, "13");
if (iLen < )
{
char bufErr[] = {};
sprintf_s(bufErr, sizeof(bufErr), "MsgHandler01(...) - (dwLen < 0) : %d", iLen);
Info_Send_pc(_hWnd, bufErr);
return false;
} //sprintf_s(buf1, sizeof(buf1), "14 : %d, %d, %d, %d", iLen, g_dwInfoRecvCnt, dwBegin, dwPos);
//Info_Send_pc(_hWnd, buf1);
Info_Send(_hWnd, iLen, &g_infoRecv[]);
//Info_Send_pc(_hWnd, "15");
memcpy( &g_infoRecv[], &g_infoRecv[iLen + ], g_dwInfoRecvCnt - (iLen+) );
//Info_Send_pc(_hWnd, "16");
g_dwInfoRecvCnt -= (iLen+);
//Info_Send_pc(_hWnd, "17");
}
return true;
}

3、

4、

5、

串口.Qt532测试(同步)的更多相关文章

  1. 串口.Qt532测试(异步)

    环境:Win7x64.Qt5.3.2 MSVC OpenGL(x86).vs2010(x86) 项目所在位置:E:\Project_Qt532\SeriesPort_Qt532_Z ZC:这里 同步方 ...

  2. C#串口编程测试收发

    原文:http://www.cnblogs.com/vsdot/archive/2013/04/23/3263348.html   基本传递方法:RS232传输要有1位起始位,8位数据位.1位校验位( ...

  3. OracleOggan安装并测试同步数据步骤!

    Oracle Golden Gate (ogg)安装使用说明 Golden Gate(简称OGG)提供异构环境下交易数据的实时捕捉.变换.投递等功能. OGG支持的异构环境有: OGG的特性: ①对生 ...

  4. Android 串口驱动和应用测试

    这篇博客主要是通过一个简单的例子来了解Android的串口驱动和应用,为方便后续对Android串口服务和USB虚拟串口服务的了解.这个例子中,参考了<Linux Device Drivers& ...

  5. 介绍三款串口监控工具:Device Monitoring Studio,portmon,Comspy

    在开发上位机下位机通讯程序时,有一个好的监控工具会事半功倍.特在网上找了几款串口监控软件,作了简单对比: 一.Device Monitoring Studio 网址:http://www.hhdsof ...

  6. unison+inotify-tools触发式双向自动同步

    双向实时数据同步部署 首先添加服务器ssh信任,即免秘钥登陆 Web1:192.168.10.36 Web2:192.168.10.37 分别在web1和web2上执行以下命令 mkdir ~/.ss ...

  7. Windows驱动——虚拟机 虚拟串口 双机调试

    =================================版权声明================================= 版权声明:原创文章 谢绝转载  请通过右侧公告中的“联系邮 ...

  8. 【Mocha.js 101】同步、异步与 Promise

    前情提要 在上一篇文章<[Mocha.js 101]Mocha 入门指南>中,我们提到了如何用 Mocha.js 进行前端自动化测试,并做了几个简单的例子来体验 Mocha.js 给我们带 ...

  9. 利用Jmeter进行Web测试

    JMeter介绍 脚本录制 运行JMeter进行测试 JMeter主要组件介绍 参数化设置 动态数据关联 使用命令行运行JMeter脚本 利用XSLT分析JMeter结果文件 1:JMeter,一个1 ...

随机推荐

  1. react复习总结(1)--react组件开发基础

    这次是年后第一次发文章,也有很长一段时间没有写文章了.准备继续写.总结是必须的. 最近一直在业余时间学习和复习前端相关知识点,在一个公司呆久了,使用的技术不更新,未来真的没有什么前景,特别是我们这种以 ...

  2. webVR框架A-frame

    A-frame:https://blog.csdn.net/sun124608666/article/details/77869570 three.js学习文档:http://www.hewebgl. ...

  3. Python文件读写、StringIO和BytesIO

    1 IO的含义 在计算机中,IO是Input/Output的简写,也就是输入和输出. 由于程序和运行时数据是在内存中驻留,由CPU这个超快的计算核心来执行,涉及到数据交换的地方,通常是磁盘.网络等,就 ...

  4. pyqt5 界面切换

    QStackedWidget 只需要关联好对应的信号和槽,调用setCurrentIndex函数,想切哪个界面就切到哪个界面

  5. 探索RequestBody报com.alibaba.fastjson.JSONObject cannot be cast to xxx

    今天使用RequestBody接受前端传过来的参数,以前接受字符串数组非常成功,这次把形参改成了List<User>,原本以为顺利接受参数并映射成User的list结构,结果竟然在我取us ...

  6. 第五章 CSS常用属性笔记

    1. span标签 突显,强调局部文字的作用. 2.字体样式 font-size: 字体大小 font-style:normal,italic(倾斜) font-weight:normal,bold( ...

  7. Spring 学习——Aware接口

    Aware 作用 Spring中提供了一些以Aware结尾的接口,实现了Aware接口的Bean在初始化后,可以通过一些接口获取相应的资源. 通过Aware接口,可以对Spring的资源进行一些操作( ...

  8. ODAC(V9.5.15) 学习笔记(三)TOraSession(4)

    4. 数据库信息 名称 类型 说明 GetDatabaseNames 获取对应的数据库对象名称列表 GetSequenceNames GetStoredProcNames GetTableNames ...

  9. Super-palindrome 【可能是暴力】

    Super-palindrome 时间限制: 1 Sec  内存限制: 128 MB 提交: 486  解决: 166 [提交] [状态] [命题人:admin] 题目描述 You are given ...

  10. hdfoo站点开发笔记-2

    httpd的目录的 Options: (里面的单词都是用的复数): Options Indexes FollowSymLinks 为了避免有些目录下没有生成deny.htm而显示列表, 可以直接给 / ...