当前位置:   article > 正文

Qt C++ TCP服务端响应多客户端通讯

Qt C++ TCP服务端响应多客户端通讯

本示例使用的设备:WIFI无线4G网络RFID云读卡器远程网络开关物流网阅读器TTS语音-淘宝网 (taobao.com)

  1. #include "mainwindow.h"
  2. #include "ui_mainwindow.h"
  3. #include "QMessageBox"
  4. #include <QDebug>
  5. #include <exception>
  6. #include <QTcpServer>
  7. #include <QTcpSocket>
  8. #include <QObject>
  9. #include <QTime>
  10. #include <QTreeWidgetItem>
  11. #include <QClipboard>
  12. bool listening=false;
  13. QTcpServer m_server;
  14. QTcpSocket m_socket;
  15. //获取本机所有网卡IP------------------------------------------------------------------------------------------------------
  16. QStringList getAllIPAddresses() {
  17. QStringList ips;
  18. QList<QHostAddress> list = QNetworkInterface::allAddresses();
  19. for (int i = 0; i < list.size(); ++i) {
  20. QHostAddress address = list.at(i);
  21. // 检查是否为IPv4地址,并排除回环地址
  22. if (address.protocol() == QAbstractSocket::IPv4Protocol && address != QHostAddress::LocalHost) {
  23. ips << address.toString();
  24. }
  25. }
  26. return ips;
  27. }
  28. //获取系统现时间-------------------------------------------------------------------------------------------------------------
  29. QString getsystime(){
  30. QTime time = QTime::currentTime();
  31. QString timeStr = time.toString("hh:mm:ss.zzz");
  32. return timeStr;
  33. }
  34. //获取系统日期时间-------------------------------------------------------------------------------------------------------------
  35. QString getsysdatetime(){
  36. QDateTime currentDateTime = QDateTime::currentDateTime();
  37. QString dateTimeString = currentDateTime.toString("yy-MM-dd hh:mm:ss");
  38. return dateTimeString;
  39. }
  40. //QByteArray转16进制QString------------------------------------------------------------------------------------------------
  41. QString ByteArrayToHexString(QByteArray data){
  42. QString ret(data.toHex().toUpper());
  43. int len = ret.length()/2;
  44. for(int i=1;i<len;i++)
  45. {
  46. ret.insert(2*i+i-1," ");
  47. }
  48. return ret;
  49. }
  50. //通讯报文显示-----------------------------------------------------------------------------------------------------
  51. void MainWindow::listadditems(int ctr,QString listinfo){
  52. switch (ctr){
  53. case 0:
  54. if(ui->listWidget_report->count()>30){
  55. ui->listWidget_report->clear();
  56. }
  57. ui->listWidget_report->addItem(listinfo);
  58. ui->listWidget_report->setCurrentRow(ui->listWidget_report->count()-1);
  59. break;
  60. case 1:
  61. ui->listWidget_online->addItem(listinfo);
  62. ui->listWidget_online->setCurrentRow(ui->listWidget_online->count()-1);
  63. }
  64. }
  65. MainWindow::MainWindow(QWidget *parent)
  66. : QMainWindow(parent)
  67. , ui(new Ui::MainWindow)
  68. {
  69. ui->setupUi(this);
  70. ui->TEPort->setPlainText("39169"); //出厂默认39169端口
  71. ui->spinBox_dispdelay->setValue(20);
  72. ui->spinBox_swit->setValue(30);
  73. ui->spinBox_voice->setValue(8);
  74. ui->textEdit_disp->setText("欢迎您使用我们的网络读卡器!");
  75. ui->textEdit_tts->setText("感谢您的使用,您的支持是我们最大的动力!");
  76. QStringList ips = getAllIPAddresses();
  77. foreach (QString ip, ips) {
  78. ui->CBIP->addItem(ip);
  79. }
  80. if(ui->CBIP->count()<1){
  81. QMessageBox::information(NULL, "提示", "未搜索到本机的网卡,系统不能正常运行!");
  82. delete ui;
  83. }
  84. }
  85. MainWindow::~MainWindow()
  86. {
  87. delete ui;
  88. }
  89. //启动、关闭TCP服务-------------------------------------------------------------------------------------------------------
  90. void MainWindow::initserver(){
  91. try{
  92. if(ui->pushButton_initserver->text()=="开启TCP服务"){
  93. QString ipstr=ui->CBIP->currentText();
  94. QHostAddress localeip(ipstr);
  95. quint16 port=ui->TEPort->toPlainText().toUInt();
  96. m_server = new QTcpServer(this);
  97. m_server->listen(localeip, port);
  98. connect(m_server, &QTcpServer::newConnection, this, &MainWindow::onNewConnection);
  99. listening=true;
  100. ui->pushButton_initserver->setText("停止");
  101. listadditems(0,getsystime()+" Tcp Server is listening...");
  102. }else{
  103. listening=false;
  104. m_server->close();
  105. ui->pushButton_initserver->setText("开启TCP服务");
  106. for(int i=0;i<tcpclientlist.count();i++){
  107. tcpclientlist.at(i)->close();
  108. //tcpclientlist.remove(i);
  109. ui->listWidget_online->takeItem(i);
  110. }
  111. tcpclientlist.clear();
  112. listadditems(0,getsystime()+" Tcp Server is close! ");
  113. }
  114. }
  115. catch(_exception)
  116. {
  117. listening=false;
  118. ui->pushButton_initserver->setText("开启TCP服务");
  119. }
  120. }
  121. //侦听到有新的TCP客户端接入服务--------------------------------------------------------------------------------------------
  122. void MainWindow::onNewConnection()
  123. {
  124. m_socket = m_server->nextPendingConnection();
  125. tcpclientlist.append(m_socket);
  126. QString RemoIp=m_socket->peerAddress().toString();
  127. QString RemoPort=QString::number( m_socket->peerPort());
  128. listadditems(1,RemoIp+":"+RemoPort);
  129. listadditems(0,getsystime()+" NewConn "+RemoIp+":"+RemoPort);
  130. connect(m_socket, &QTcpSocket::readyRead, this, &MainWindow::onReadyRead);
  131. connect(m_socket, &QTcpSocket::disconnected, this, &MainWindow::onClientDisconnected);
  132. connect(m_socket, &QTcpSocket::connected, this, &MainWindow::onConnected);
  133. // connect(m_socket, &QTcpSocket::stateChanged, this, &MainWindow::onStateChanged);
  134. }
  135. //接收到TCP客户端传送来来的数据-------------------------------------------------------------------------------------------
  136. void MainWindow::onReadyRead()
  137. {
  138. QByteArray buffer;
  139. for(int row=0;row<tcpclientlist.count();row++){
  140. m_socket=tcpclientlist.at(row);
  141. buffer = m_socket->readAll();
  142. if(buffer.length()!=0){
  143. QString RemoIp=m_socket->peerAddress().toString();
  144. QString RemoPort=QString::number( m_socket->peerPort());
  145. listadditems(0,getsystime()+" Receive: "+RemoIp+":"+RemoPort+" "+ByteArrayToHexString(buffer));
  146. unsigned char databuff[buffer.length()];
  147. std::copy(buffer.begin(), buffer.end(), databuff);
  148. switch (databuff[0]){
  149. case 0xc1:
  150. case 0xcf:
  151. Analyze_c1_cf(row,databuff,buffer.length()); //解析读取IC卡卡号
  152. break;
  153. case 0xd1:
  154. case 0xdf:
  155. Analyze_d1_df(row,databuff,buffer.length()); //解析读取ID卡卡号
  156. break;
  157. default:
  158. break;
  159. }
  160. }
  161. }
  162. }
  163. //侦测到TCP客户端断开连接---------------------------------------------------------------------------------------------
  164. void MainWindow::onClientDisconnected()
  165. {
  166. QString RemoIp=m_socket->peerAddress().toString();
  167. quint16 RemoPort= m_socket->peerPort();
  168. for(int i=0;i<tcpclientlist.count();i++){
  169. if(tcpclientlist.at(i)->peerAddress().toString()==RemoIp && tcpclientlist.at(i)->peerPort()==RemoPort){
  170. tcpclientlist.remove(i);
  171. ui->listWidget_online->takeItem(i);
  172. listadditems(0,getsystime()+" Disconn: "+RemoIp+":"+QString::number(RemoPort));
  173. }
  174. }
  175. }
  176. void MainWindow::onConnected()
  177. {
  178. QString RemoIp=m_socket->peerAddress().toString();
  179. QString RemoPort=QString::number( m_socket->peerPort());
  180. }
  181. //void MainWindow::onStateChanged(QAbstractsocket::SocketState socketstate){
  182. // switch (socketstate){
  183. // case QAbstractSocket::UnconnectedState:ui->labConnectState->setText("Unconnectedstate");break;
  184. // case QAbstractSocket::HostLookupState:ui->labConnectState->setText("HostLookupstate");break;
  185. // case QAbstractSocket::ConnectedState:ui->labConnectState->setText("connectedstate");break;
  186. // case QAbstractSocket::ConnectingState:ui->labConnectState->setText("connectingstate");break;
  187. // case QAbstractSocket::BoundState: ui->labConnectState->setText("Boundstate");break;
  188. // case QAbstractSocket::ClosingState:ui->labConnectState->setText("closingstate");break;
  189. // case QAbstractSocket::ListeningState:ui->labConnectState->setText("listeningstate");break;
  190. // }
  191. //}
  192. //解析读取IC卡卡号-------------------------------------------------------------------------------------------------------------------
  193. void MainWindow::Analyze_c1_cf(int socketid,unsigned char databuff[], qint64 buflen)
  194. {
  195. QString IPAddress=QString::asprintf("%d", databuff[1])+"."+QString::asprintf("%d", databuff[2])+"."+QString::asprintf("%d", databuff[3])+"."+QString::asprintf("%d", databuff[4]); //设备IP地址,广域网上使用,一般不对此IP回应,而是对数据流的 ip及端口 回应
  196. QString DeviceNumber=QString::asprintf("%05d",databuff[5]+databuff[6]*256); //设备自编机号
  197. QString FrameNumber=QString::asprintf("%05d",databuff[7]+databuff[8]*256); //数据包号
  198. int cardnolen=databuff[9];
  199. QString CardnoHexZ=""; //16进制卡号正码
  200. QString CardnoHexF=""; //16进制卡号反码
  201. for (int i=0;i<cardnolen;i++){
  202. CardnoHexZ=CardnoHexZ+QString::asprintf("%02X", databuff[10+i]);
  203. if(i<4){CardnoHexF=CardnoHexF+QString::asprintf("%02X", databuff[9+cardnolen-i]);} //只取4个字节计算8H10D反码
  204. }
  205. QString SerialNumber=""; //设备全球唯一硬件序号
  206. for (int i=10+cardnolen;i<buflen;i++){
  207. SerialNumber=SerialNumber+QString::asprintf("%02X", databuff[i]);
  208. }
  209. bool status;
  210. QString Cardno8H10D=QString::asprintf("%010u",CardnoHexF.toUInt(&status,16)); //转8H10D反码卡号
  211. QString DispInf;
  212. if (databuff[0]==0xc1){DispInf="读取IC卡号,";}else{DispInf="IC卡离开读卡器,";}
  213. DispInf=DispInf+"设备IP:"+IPAddress+",机号:"+DeviceNumber+",数据包号:"+FrameNumber+",16进制卡号:"+CardnoHexZ+",转8H10D反码:"+Cardno8H10D+",设备全球唯一序号:"+SerialNumber;
  214. ui->plainTextEdit_msg->setPlainText(DispInf);
  215. if(ui->checkBox_Resp->isChecked()){Respondinfo(socketid,getsysdatetime()+"卡号:"+Cardno8H10D);} //回应驱动设备显示+蜂鸣响声
  216. }
  217. //解析读取ID卡卡号-------------------------------------------------------------------------------------------------------------------
  218. void MainWindow::Analyze_d1_df(int socketid,unsigned char databuff[], qint64 buflen)
  219. {
  220. QString IPAddress=QString::asprintf("%d", databuff[1])+"."+QString::asprintf("%d", databuff[2])+"."+QString::asprintf("%d", databuff[3])+"."+QString::asprintf("%d", databuff[4]); //设备IP地址,广域网上使用,一般不对此IP回应,而是对数据流的 ip及端口 回应
  221. QString DeviceNumber=QString::asprintf("%05d",databuff[5]+databuff[6]*256); //设备自编机号
  222. QString FrameNumber=QString::asprintf("%05d",databuff[7]+databuff[8]*256); //数据包号
  223. QString CardnoHexZ=""; //16进制卡号正码
  224. QString CardnoHexF=""; //16进制卡号反码
  225. for (int i=0;i<5;i++){
  226. CardnoHexZ=CardnoHexZ+QString::asprintf("%02X", databuff[9+i]);
  227. if(i<4){CardnoHexF=CardnoHexF+QString::asprintf("%02X", databuff[9+3-i]);} //只取4个字节计算8H10D反码
  228. }
  229. QString SerialNumber=""; //设备全球唯一硬件序号
  230. for (int i=9+5;i<buflen;i++){
  231. SerialNumber=SerialNumber+QString::asprintf("%02X", databuff[i]);
  232. }
  233. bool status;
  234. QString Cardno8H10D=QString::asprintf("%010u",CardnoHexF.toUInt(&status,16)); //转8H10D反码卡号
  235. QString DispInf;
  236. if (databuff[0]==0xd1){DispInf="读取ID卡号,";}else{DispInf="ID卡离开读卡器,";}
  237. DispInf=DispInf+"设备IP:"+IPAddress+",机号:"+DeviceNumber+",数据包号:"+FrameNumber+",16进制卡号:"+CardnoHexZ+",转8H10D反码:"+Cardno8H10D+",设备全球唯一序号:"+SerialNumber;
  238. ui->plainTextEdit_msg->setPlainText(DispInf);
  239. if(ui->checkBox_Resp->isChecked()){Respondinfo(socketid,getsysdatetime()+"卡号:"+Cardno8H10D);} //回应驱动设备显示+蜂鸣响声
  240. }
  241. void MainWindow::on_btnClose_clicked()
  242. {
  243. m_server->close();
  244. }
  245. //向指定的客户端发送数据--------------------------------------------------------------------------------------------------------------
  246. void MainWindow::SendBufToSockID(int socketid,QByteArray rbuffer){
  247. m_socket=tcpclientlist.at(socketid);
  248. m_socket->write(rbuffer);
  249. QString RemoIp=m_socket->peerAddress().toString();
  250. QString RemoPort=QString::number( m_socket->peerPort());
  251. QString SendHex=getsystime()+" Send To: "+(RemoIp+":"+RemoPort+" ").mid(0,22);
  252. SendHex=SendHex+ByteArrayToHexString(rbuffer);
  253. listadditems(0,SendHex);
  254. }
  255. void MainWindow::on_pushButton_initserver_clicked()
  256. {
  257. initserver();
  258. }
  259. //驱动读卡器蜂鸣响声-----------------------------------------------------------------------
  260. void MainWindow::on_btnSendbeep_clicked()
  261. {
  262. QListWidgetItem *item = ui->listWidget_online->currentItem();
  263. int row = ui->listWidget_online->row(item);
  264. if(row<0){
  265. QMessageBox::critical(this, "警告", "请选择一台在线设备再执行此功能!", QMessageBox::Ok);
  266. }else{
  267. QByteArray sendData;
  268. sendData.append(0x96); //功能码
  269. quint16 devno=0;
  270. sendData.append(devno % 256); //机号低位
  271. sendData.append(devno / 256); //机号高位,高低位都为0表示任意机号
  272. sendData.append(ui->CBbeep->currentIndex()); //蜂鸣响声代码
  273. SendBufToSockID(row,sendData);
  274. }
  275. }
  276. //驱动读卡器开启继电器-----------------------------------------------------------------------
  277. void MainWindow::on_btnswitchon_clicked()
  278. {
  279. QListWidgetItem *item = ui->listWidget_online->currentItem();
  280. int row = ui->listWidget_online->row(item);
  281. if(row<0){
  282. QMessageBox::critical(this, "警告", "请选择一台在线设备再执行此功能!", QMessageBox::Ok);
  283. }else{
  284. QByteArray sendData;
  285. sendData.append(0x78); //功能码
  286. quint16 devno=0;
  287. sendData.append(devno % 256); //机号低位
  288. sendData.append(devno / 256); //机号高位,高低位都为0表示任意机号
  289. QString swithno="F"+QString::asprintf("%d",ui->CBSwitch->currentIndex());
  290. bool status;
  291. sendData.append(swithno.toUInt(&status,16)); //选择继电器
  292. quint16 deltime=ui->spinBox_swit->value();
  293. sendData.append(deltime % 256); //开启延时低位
  294. sendData.append(deltime / 256); //开启延时高位
  295. SendBufToSockID(row,sendData);
  296. }
  297. }
  298. //驱动读卡器关闭已开启的继电器-----------------------------------------------------------------
  299. void MainWindow::on_btnswitchoff_clicked()
  300. {
  301. QListWidgetItem *item = ui->listWidget_online->currentItem();
  302. int row = ui->listWidget_online->row(item);
  303. if(row<0){
  304. QMessageBox::critical(this, "警告", "请选择一台在线设备再执行此功能!", QMessageBox::Ok);
  305. }else{
  306. QByteArray sendData;
  307. sendData.append(0x78); //功能码
  308. quint16 devno=0;
  309. sendData.append(devno % 256); //机号低位
  310. sendData.append(devno / 256); //机号高位,高低位都为0表示任意机号
  311. QString swithno="E"+QString::asprintf("%d",ui->CBSwitch->currentIndex());
  312. bool status;
  313. sendData.append(swithno.toUInt(&status,16)); //选择继电器
  314. quint16 deltime=ui->spinBox_swit->value();
  315. sendData.append(deltime % 256); //开启延时低位
  316. sendData.append(deltime / 256); //开启延时高位
  317. SendBufToSockID(row,sendData);
  318. }
  319. }
  320. //驱动读卡器蜂鸣响声并显示文字---------------------------------------------------------------------
  321. void MainWindow::on_btnDispbeep_clicked()
  322. {
  323. QListWidgetItem *item = ui->listWidget_online->currentItem();
  324. int row = ui->listWidget_online->row(item);
  325. if(row<0){
  326. QMessageBox::critical(this, "警告", "请选择一台在线设备再执行此功能!", QMessageBox::Ok);
  327. }else{
  328. QByteArray sendData;
  329. sendData.append(0x5A); //功能码
  330. quint16 devno=0;
  331. sendData.append(devno % 256); //机号低位
  332. sendData.append(devno / 256); //机号高位,高低位都为0表示任意机号
  333. sendData.append(ui->CBbeep->currentIndex()); //蜂鸣响声代码,255表示不响声
  334. sendData.append(ui->spinBox_dispdelay->value()); //文字显示时长,
  335. QString dispstr=ui->textEdit_disp->toPlainText()+" "; //加空格是为了确保满屏34位显示
  336. QByteArray Dispbyte=dispstr.toLocal8Bit();
  337. for(int i=0;i<34;i++){
  338. sendData.append(Dispbyte[i]);
  339. }
  340. SendBufToSockID(row,sendData);
  341. }
  342. }
  343. //驱动读卡器蜂鸣响声+显示文字+播报TTS语音+开启继电器开关
  344. void MainWindow::on_btndispbeeptts_clicked()
  345. {
  346. QListWidgetItem *item = ui->listWidget_online->currentItem();
  347. int row = ui->listWidget_online->row(item);
  348. if(row<0){
  349. QMessageBox::critical(this, "警告", "请选择一台在线设备再执行此功能!", QMessageBox::Ok);
  350. }else{
  351. if(ui->spinBox_voice->value()>16){ui->spinBox_voice->setValue(16);} //tts最大语音取值16
  352. QString strls="[v"+QString::asprintf("%d",ui->spinBox_voice->value())+"]";
  353. strls=strls+ui->textEdit_tts->toPlainText().trimmed();
  354. QByteArray SpeakArr=strls.toLocal8Bit(); //TS语音转换为Ansi码
  355. quint8 speakbytes=SpeakArr.size();
  356. quint8 dispbytes=34; //双行显示屏显示长度34,四行屏显示长度72
  357. QByteArray sendData;
  358. sendData.append(0x5c); //功能码
  359. quint16 devno=0;
  360. sendData.append(devno % 256); //机号低位
  361. sendData.append(devno / 256); //机号高位,高低位都为0表示所有机
  362. sendData.append(ui->CBbeep->currentIndex()); //蜂鸣响声代码,取值255表示不响
  363. QString swithno="F"+QString::asprintf("%d",ui->CBSwitch->currentIndex());
  364. bool status;
  365. sendData.append(swithno.toUInt(&status,16)); //选择继电器
  366. quint16 deltime=ui->spinBox_swit->value();
  367. sendData.append(deltime % 256); //延时低位
  368. sendData.append(deltime / 256); //延时高位
  369. sendData.append(ui->spinBox_dispdelay->value()); //文字显示时长,
  370. quint8 begindisp =0; //在显示屏中的哪个位置开始显示,一般取0
  371. sendData.append(begindisp);
  372. sendData.append(dispbytes); //显示文字长度
  373. sendData.append(speakbytes); //tts语音长茺
  374. QString dispstr=ui->textEdit_disp->toPlainText()+" "; //加空格是为了确保满屏34位显示
  375. QByteArray Dispbyte=dispstr.toLocal8Bit();
  376. for(int i=0;i<dispbytes;i++){
  377. sendData.append(Dispbyte[i]); //显示信息
  378. }
  379. for(int i=0;i<speakbytes;i++){
  380. sendData.append(SpeakArr[i]); //TTS语音信息
  381. }
  382. sendData.append(0x55); //防干扰后缀
  383. sendData.append(0xaa);
  384. sendData.append(0x66);
  385. sendData.append(0x99);
  386. SendBufToSockID(row,sendData);
  387. }
  388. }
  389. //接收到刷卡数据立即回应--------------------------------------------------------------------------
  390. void MainWindow::Respondinfo(int socketid,QString Dispinf)
  391. {
  392. QByteArray RespBuff;
  393. RespBuff.append(0x5A); //功能码
  394. quint16 devno=0;
  395. RespBuff.append(devno % 256); //机号低位
  396. RespBuff.append(devno / 256); //机号高位,高低位都为0表示任意机
  397. RespBuff.append(ui->CBbeep->currentIndex()); //蜂鸣响声代码,255表示不响声
  398. RespBuff.append(ui->spinBox_dispdelay->value()); //文字显示时长,
  399. QString dispstr=Dispinf+" "; //加空格是为了确保满屏34位显示
  400. QByteArray Dispbyte=dispstr.toLocal8Bit();
  401. for(int i=0;i<34;i++){
  402. RespBuff.append(Dispbyte[i]);
  403. }
  404. m_socket=tcpclientlist.at(socketid);
  405. m_socket->write(RespBuff);
  406. QString RemoIp=m_socket->peerAddress().toString();
  407. QString RemoPort=QString::number( m_socket->peerPort());
  408. QString SendHex=getsystime()+" Send To: "+(RemoIp+":"+RemoPort+" ").mid(0,22);
  409. SendHex=SendHex+ByteArrayToHexString(RespBuff);
  410. listadditems(0,SendHex);
  411. }
  412. void MainWindow::on_btncopyreport_clicked()
  413. {
  414. QString listinf;
  415. int row=ui->listWidget_report->count();
  416. if (row<1){
  417. return;
  418. }else{
  419. for (int i=0;i<row;i++){
  420. QListWidgetItem *item = ui->listWidget_report->item(i);
  421. listinf=listinf+item->text()+"\n";
  422. }
  423. QClipboard *clipboard = QApplication::clipboard();
  424. clipboard->setText(listinf);
  425. QMessageBox::information(this, "提示", "显示数据报文已拷贝到剪切板");
  426. }
  427. }

源码下载 :https://download.csdn.net/download/zhangjin7422/89421064

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/704244
推荐阅读
相关标签
  

闽ICP备14008679号