QT示例:基于TCP 点对多Socket通讯(server,clients)

QT示例:基于TCP 点对多通讯(server,clients)

      • 一、服务器server
      • 二、客户端Client

下载:基于TCP 点对多Socket通讯

一、服务器server

因为对于客户端来说,只能连接一个服务器。而对于服务器来说,它是面向多连接的,如何协调处理多客户端连接就显得尤为重要。

  • 注意问题:
    每个新加入的客户端,服务器给其分配一个SocketDescriptor后,就会emit newConnection()信号,但分配好的SocketDecriptor并没有通过newConnection()信号传递,所以用户得不到这个客户端标识SocketDescriptor。同样的,每当服务器收到新的消息时,客户端会emit readReady()信号,然而readReady()信号也没有传递SocketDescriptor, 这样的话,服务器端即使接收到消息,也不知道这个消息是从哪个客户端发出的。
  • 解决的方法:
  1. 通过重写==[virtual protected] void QTcpServer::incomingConnection(qintptr socketDescriptor)==,获取soketDescriptor。自定义TcpClient类继承QTcpSocket,并将获得的soketDescriptor作为类成员。 这个方法的优点是:可以获取到soketDescriptor,灵活性高。缺点是:需要重写函数、自定义类。
  2. 在newConnection()信号对应的槽函数中,通过QTcpSocket *QTcpServer::nextPendingConnection()函数获取 新连接的客户端:Returns the next pending connection as a connected QTcpSocket object. 虽然仍然得不到soketDescriptor,**但可以通过QTcpSocket类的peerAddress()和peerPort()成员函数获取客户端的IP和端口号,同样是唯一标识。 **优点:无需重写函数和自定义类,代码简洁。缺点:无法获得SocketDecriptor,灵活性差。

本文示例为第二种方法:
1).pro 添加:

QT       += network

2)主函数 main.cpp 添加:

#include "mytcpserver.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MyTcpServer w;w.show();return a.exec();
}

3)MyTcpServer.h 添加:

#include "mytcpserver.h"
#include "ui_mytcpserver.h"MyTcpServer::MyTcpServer(QWidget *parent) :QMainWindow(parent),ui(new Ui::MyTcpServer)
{ui->setupUi(this);//  一 、创建QTcpSever对象;tcpServer = new QTcpServer(this);ui->edtIP->setText(QNetworkInterface().allAddresses().at(1).toString());   //获取本地IPui->btnConnect->setEnabled(true);ui->btnSend->setEnabled(false);// 设置默认按钮样式ui->btnConnect->setStyleSheet("");connect(tcpServer, &QTcpServer::newConnection, this, &MyTcpServer::NewConnectionSlot);
}MyTcpServer::~MyTcpServer()
{delete ui;
}// 二、监听--断开
void MyTcpServer::on_btnConnect_clicked()
{if(ui->btnConnect->text()=="监听"){bool ok = tcpServer->listen(QHostAddress::Any, ui->edtPort->text().toInt());if(ok){ui->btnConnect->setText("断开");ui->btnConnect->setStyleSheet("color: red;");ui->btnSend->setEnabled(true);}}else{for(int i=0; i<tcpClient.length(); i++) // 断开所有连接{tcpClient[i]->disconnectFromHost();bool ok = tcpClient[i]->waitForDisconnected(1000);if(!ok){// 处理异常QMessageBox::warning(this, tr("错误"),tr("断开连接失败!"), QMessageBox::Ok);}tcpClient.removeAt(i);  // 从保存的客户端列表中取去除}tcpServer->close();     // 不再监听端口ui->btnConnect->setText("监听");ui->btnConnect->setStyleSheet("");ui->btnSend->setEnabled(false);}
}// 三、新连接建立的槽函数
void MyTcpServer::NewConnectionSlot()
{currentClient = tcpServer->nextPendingConnection();tcpClient.append(currentClient);ui->cbxConnection->addItem(tr("%1:%2").arg(currentClient->peerAddress().toString().split("::ffff:")[1]).arg(currentClient->peerPort()));connect(currentClient, &QTcpSocket::readyRead, this,  &MyTcpServer::ReadData);connect(currentClient, &QTcpSocket::disconnected, this,  &MyTcpServer::disconnectedSlot);
}// 四、客户端数据可读信号,对应的读数据槽函数
void MyTcpServer::ReadData()
{// 由于readyRead信号并未提供SocketDecriptor,所以需要遍历所有客户端for(int i=0; i<tcpClient.length(); i++){QByteArray buffer = tcpClient[i]->readAll();if(buffer.isEmpty())    // 客户端 数据为空,则跳过continue;// 客户端有数据则 获取IP 和端口static QString IP_Port, IP_Port_Pre;IP_Port = tr("[%1:%2]:").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]).arg(tcpClient[i]->peerPort());// 若此次消息的地址与上次不同,则需显示此次消息的客户端地址if(IP_Port != IP_Port_Pre)ui->edtRecv->append(IP_Port);ui->edtRecv->append(buffer);//更新ip_portIP_Port_Pre = IP_Port;}
}// 五、断开连接的槽函数
void MyTcpServer::disconnectedSlot()
{//由于disconnected信号并未提供SocketDescriptor,所以需要遍历寻找for(int i=0; i<tcpClient.length(); i++){if(tcpClient[i]->state() == QAbstractSocket::UnconnectedState){// 删除存储在combox中的客户端信息ui->cbxConnection->removeItem(ui->cbxConnection->findText(tr("%1:%2").arg(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]).arg(tcpClient[i]->peerPort())));// 删除存储在tcpClient列表中的客户端信息tcpClient[i]->destroyed();tcpClient.removeAt(i);}}
}// 六、发送数据
void MyTcpServer::on_btnSend_clicked()
{QString data = ui->edtSend->toPlainText();if(data == "")return;    // 文本输入框为空时//全部连接if(ui->cbxConnection->currentIndex() == 0){for(int i=0; i<tcpClient.length(); i++)tcpClient[i]->write(data.toLatin1()); //qt5除去了.toAscii()}//指定连接else{QString clientIP = ui->cbxConnection->currentText().split(":")[0];  // IP 地址int clientPort = ui->cbxConnection->currentText().split(":")[1].toInt();    // port 端口号
//        qDebug() << clientIP;
//        qDebug() << clientPort;for(int i=0; i<tcpClient.length(); i++){if(tcpClient[i]->peerAddress().toString().split("::ffff:")[1]==clientIP&& tcpClient[i]->peerPort()==clientPort){tcpClient[i]->write(data.toLatin1());return; //ip:port唯一,无需继续检索}}}
}// 清楚窗口
void MyTcpServer::on_btnClear_clicked()
{ui->edtRecv->clear();
}

5)界面 mytcpserver.ui
在这里插入图片描述
在这里插入图片描述

二、客户端Client

1).pro 添加:

QT       += network

2)主函数 main.cpp 添加:

#include "mytcpclient.h"
#include <QApplication>int main(int argc, char *argv[])
{QApplication a(argc, argv);MyTcpClient w;w.show();return a.exec();
}

3)MyTcpClient.h 添加:

#include <QMainWindow>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>namespace Ui {
class MyTcpClient;
}class MyTcpClient : public QMainWindow
{Q_OBJECTpublic:explicit MyTcpClient(QWidget *parent = 0);~MyTcpClient();private:Ui::MyTcpClient *ui;QTcpSocket *tcpClient;private slots://客户端槽函数void ReadData();void ReadError(QAbstractSocket::SocketError);void on_btnConnect_clicked();void on_btnSend_clicked();void on_pushButton_clicked();
};

4)MyTcpClient.cpp 添加:

#include "mytcpclient.h"
#include "ui_mytcpclient.h"MyTcpClient::MyTcpClient(QWidget *parent) :QMainWindow(parent),ui(new Ui::MyTcpClient)
{ui->setupUi(this);// 一、初始化TCP客户端tcpClient = new QTcpSocket(this);   //实例化tcpClienttcpClient->abort();                 //取消原有连接ui->btnConnect->setEnabled(true);ui->btnSend->setEnabled(false);connect(tcpClient, &QTcpSocket::readyRead, this, &MyTcpClient::ReadData);connect(tcpClient, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(ReadError(QAbstractSocket::SocketError)));
}MyTcpClient::~MyTcpClient()
{delete ui;
}// 二、连接
void MyTcpClient::on_btnConnect_clicked()
{if(ui->btnConnect->text()=="连接"){tcpClient->connectToHost(ui->edtIP->text(), ui->edtPort->text().toInt());if (tcpClient->waitForConnected(1000))  // 连接成功则进入if{}{ui->btnConnect->setText("断开");ui->btnSend->setEnabled(true);}}else{tcpClient->disconnectFromHost();if (tcpClient->state() == QAbstractSocket::UnconnectedState || tcpClient->waitForDisconnected(1000))  //已断开连接则进入if{}{ui->btnConnect->setText("连接");ui->btnSend->setEnabled(false);}}
}// 三、读取数据
void MyTcpClient::ReadData()
{QByteArray buffer = tcpClient->readAll();if(!buffer.isEmpty()){ui->edtRecv->append(buffer);}
}// 四、发送数据
void MyTcpClient::on_btnSend_clicked()
{QString data = ui->edtSend->toPlainText();if(data != ""){tcpClient->write(data.toLatin1()); //qt5出去了.toAscii()}
}// 连接错误信息处理
void MyTcpClient::ReadError(QAbstractSocket::SocketError)
{tcpClient->disconnectFromHost();ui->btnConnect->setText(tr("连接"));QMessageBox msgBox;msgBox.setText(tr("failed to connect server because %1").arg(tcpClient->errorString()));msgBox.exec();
}// 清空按钮
void MyTcpClient::on_pushButton_clicked()
{ui->edtRecv->clear();
}

2)mytcpclient.ui 添加
在这里插入图片描述
在这里插入图片描述
参考博客:
QT 之TCP网络编程

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

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

相关文章

MATLAB GUI的CreateFcn如何创建

看MATLAB关于GUI代码的时候发现有一些function _CreateFcn(hObject, eventdata, handles)函数&#xff0c;那么这类函数是如何创建出出来的呢&#xff1f; 首先在MATLAB中输入guide&#xff0c;打开其中一个GUI文件&#xff0c;现在随便打开一个我之前创建好的GUI&#xff1a;…

文小刚:量子革命是最不可思议的物理革命

来源&#xff1a;科学网人类生活在一个怎样的世界里&#xff1f;凝聚态理论物理学家、美国麻省理工学院终身教授、美国科学院院士文小刚的答案是&#xff1a;“我们生活在量子计算机里面。量子信息是真实的&#xff0c;而所看到的各种物质、人&#xff0c;都是量子信息的虚拟反…

QT+Halcon综合示例:clip回形针2D位姿检测

QTHalcon综合示例&#xff08;一&#xff09;&#xff1a;clip回形针2D位姿检测0、halcon源码&#xff1a;1、Qt代码&#xff1a;2、运行结果&#xff1a;下载&#xff1a;clip回形针2D位姿检测 0、halcon源码&#xff1a; * clip.hdev: Orientation of clips * dev_close_w…

MATLAB GUI如何创建Callback函数

本文以创建按钮的Callback函数为例介绍了在MATLAB如何在GUI中创建Callback函数 首先在MATLAB中输入guide&#xff0c;打开GUI文件&#xff0c;这里我随机打开一个我之前创建的GUI文件&#xff1a; 假设现在要创建start按钮的Callback函数&#xff0c;则双击该按钮&#xff0c;…

互联网50年:从信息高速公路到超级智能的进化

来源&#xff1a;战略前沿技术编者按&#xff1a;2019年&#xff0c;迎来互联网诞生50周年。本文根据中信出版社7月出版的《崛起的超级智能&#xff1a;互联网大脑如何影响科技未来》一书的内容和观点&#xff0c;重点阐述了互联网是如何在50年中发生重大变化&#xff0c;如何促…

MATLAB摄像头可以运行但是打不开视频

今天在学习一个MATLAB关于摄像头操作的代码&#xff0c;运行之后摄像头会一闪一闪&#xff0c;但是就是打不开视频的画面&#xff0c;查看了半天代码发现代码也没有错&#xff0c;最后尝试着将代码中的下面这句中的320x240改为640x480就可以打开视频了 vid videoinput(winvid…

大脑简史(2)-研究大脑的手段

来源&#xff1a;人机与认知实验室上篇文章笔者和大家分享了认知神经科学历史上的大事件&#xff0c;这些大事件有的极大程度的改变了人们的思维&#xff0c;有的直接推动了神经科学的发展&#xff0c;可以这么说&#xff0c;没有这些前人的努力&#xff0c;就没有我们现在取得…

stm32_DMA采集一个AD数据_并通过DMA向串口发送

这是以前学32的时候写的&#xff0c;那时候学了32之后感觉32真是太强大了&#xff0c;比51强的没影。关于dma网上有许多的资料&#xff0c;关于dma采集ad网上也有很多。亲们搜搜&#xff0c;这里只贴代码了&#xff0c;其实我也想详详细细地叙述一番&#xff0c;但是自己本身打…

QT综合示例:QT串口通信

QT综合示例&#xff1a;QT串口通信0、界面&#xff1a;1、代码&#xff1a;如果用qt写程序作为上位机&#xff0c;然后通过和usb和下位机通信的时候&#xff0c;就需要用到qt中的串口通信了。 0、界面&#xff1a; 1、代码&#xff1a; 1&#xff09;.pro 添加&#xff1a; …

MATLAB GUI如何制作下拉列表

MATLAB在GUI中可以实现下图所示的下拉列表&#xff1a; 方法&#xff1a; 在MATLAB中输入guide打开一个现有的GUI或者新建一个GUI放置一个弹出式菜单&#xff0c;如图所示双击新建的弹出式菜单&#xff0c;打开检查器&#xff0c;点击检查器的“string”菜单栏右侧的按钮&…

如果每个人都是一个粒子…… | 从物理学中寻找社会规律

来源&#xff1a;环球科学人类的许多社会行为似乎是难以捉摸的&#xff0c;包括经济、交通、个人选择。不少科学家尝试从物理的角度解释人类社会&#xff0c;他们将人比作粒子&#xff0c;每个个体之间的行为、选择都会互相影响。就像物理粒子会受到不同类型的力的控制&#xf…

猎豹MFC--文件对话框CFileDialog

如下叫做打开文件对话框&#xff1a;CFileDialog类在对话框上添加文本框&#xff0c;接收回车键设置&#xff0c;多行&#xff0c;编辑修改ID&#xff0c;垂直滚动条 水平滚动条 属性设置。添加菜单资源&#xff1a;这个菜单是给主窗口使用的&#xff0c;所以在主窗口对话框属…

MATLAB的GUI界面不显示XY坐标轴

在GUI中创建一个坐标轴&#xff0c;默认会显示XY坐标&#xff0c;如下图&#xff1a; 如何关闭XY坐标轴呢&#xff1f; 首先在打开GUI界面&#xff0c;双击该坐标轴&#xff0c;在Xcolor和Ycolor中选择白色&#xff0c;将坐标轴设置为白色&#xff1a; 然后在xticklabel和ytic…

机器人工作原理的超详细解析,生动、形象!

来源&#xff1a;笑看国际风云很多人一听到“机器人”这三个字脑中就会浮现“外形酷炫”、“功能强大”、“高端”等这些词&#xff0c;认为机器人就和科幻电影里的“终结者”一样高端炫酷。其实不然&#xff0c;在本文中&#xff0c;我们将探讨机器人学的基本概念&#xff0c;…

数字图像处理:图像变换的基本模型

数字图像处理&#xff1a;图像变换的基本模型 一、常用图象的变换模型 变换模型是指根据待匹配图像与背景图像之间几何畸变的情况&#xff0c;所选择的能最佳拟合两幅图像之间变化的几何变换模型。可采用的变换模型有如下几种:刚性变换、仿射变换、透视变换和非线形变换等&am…

Nginx 的线程池与性能剖析【转载】

正如我们所知&#xff0c;NGINX采用了异步、事件驱动的方法来处理连接。这种处理方式无需&#xff08;像使用传统架构的服务器一样&#xff09;为每个请求创建额外的专用进程或者线程&#xff0c;而是在一个工作进程中处理多个连接和请求。为此&#xff0c;NGINX工作在非阻塞的…

Halcon算子学习:XLD几种边缘连接函数

Halcon算子学习&#xff1a;XLD几种边缘连接函数 1.union_cotangential_contours_xld (Contours : UnionContours : FitClippingLength, FitLength, MaxTangAngle, MaxDist, MaxDistPerp, MaxOverlap, Mode : ) 根据输入的轮廓的端点处的局部曲率&#xff0c;连接曲率满足一定…

交换机与路由器大战已结束,超大规模计算公司胜出

来源&#xff1a;云头条作者&#xff1a;Timothy Prickett Morgan是The Next Platform的联合创始人兼合作编辑。很难说会先发生什么&#xff1a;交换和路由将合并&#xff0c;还是说会出现两种功能兼具的独立网络操作系统。Arrcus去年7月推出了一种可在商用芯片上同时提供交换功…

MATLAB的GUI中给坐标轴四周加上边框

在MATLAB的GUI中如何为坐标轴四边加上方框&#xff0c;效果如下图&#xff1a; 首先打开一个GUI文件&#xff0c;建立一个坐标轴&#xff0c;如下图所示&#xff1a; 双击该坐标轴&#xff0c;在弹出的检查器中&#xff0c;在Box那一栏后面勾上&#xff0c;如下图所示&#xff…

Halcon学习笔记:Halcon标定步骤-3d_coordinates.hdev示例

Halcon标定步骤 1.设置相机内部参数的初始值 StartCamPar : [0.016,0,0.0000074,0.0000074,326,247,652,494] set_calib_data_cam_param (CalibDataID, 0, ‘area_scan_division’, StartCamPar) 1.1 相机型号 &#xff08;1&#xff09;面阵&#xff08;2&#xff09;线阵…