Qt的TCP通信

您所在的位置:网站首页 incomingconnection函数 Qt的TCP通信

Qt的TCP通信

2023-07-12 11:12| 来源: 网络整理| 查看: 265

Qt的TCP通信—服务端的实现

TCP通信必须先建立TCP连接,分为客户端和服务端,Qt提供了QTSocket类和QTcpServer类用于建立TCP通信应用程序。

客户端和服务端TCP通信示意图:

在这里插入图片描述

Qt的QTcpServer类的介绍

QTcpServer是从QObject继承的类,他主要用于服务器简历网络监听,创建网络Socket连接。其主要接口函数如图所示。

在这里插入图片描述

Qt的QTcpSocket类的介绍

QTcpSocket是从QIODevice间接继承的类,具有流读写的功能,他除了构造函数和析构函数,其他函数都是从QAbstractSocket继承或重定义的。其主要函数接口如下图所示。

在这里插入图片描述

服务端的实现流程

​ 服务器端首先要用QTcpServer::listen()开始服务端监听,可以指定监听的IP地址和端口,一般一个服务程序只监听某个端口的网络连接。

​ 当有客户端接入时,QTcpServer的内部incomingConnection()函数回创建一个与客户端连接QTcpSocket对象,然后发射信号newConnection()。在newConnection()信号的槽函数中,可以用nextPendingConnection()接受客户端的连接,然后使用QTcpSocket与客户端连接通信。

TCPServer程序的运行界面如图所示

在这里插入图片描述

实现的功能:

​ 1、根据IP地址和端口打开网络监听,有客户端连接时创建socket连接

​ 2、采用基于行的数据通信协议,可以接收客户端发来的消息,也可以向客户端发送消息

​ 3、在状态栏显示服务器监听状态和socket状态

TCP服务端代码实现

mainwindow.h的实现

#ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include namespace Ui { class MainWindow; } class MainWindow : public QMainWindow { Q_OBJECT private: QLabel *LabListen;//状态栏标签 QLabel *LabSocketState;//状态栏标签 QTcpServer *tcpServer; //TCP服务器 QTcpSocket *tcpSocket;//TCP通讯的Socket QString getLocalIP();//获取本机IP地址 protected: void closeEvent(QCloseEvent *event); public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private slots: //自定义槽函数 void onNewConnection();//QTcpServer的newConnection()信号 void onSocketStateChange(QAbstractSocket::SocketState socketState); void onClientConnected(); //Client Socket connected void onClientDisconnected();//Client Socket disconnected void onSocketReadyRead();//读取socket传入的数据 //UI生成的 void on_actStart_triggered(); void on_actStop_triggered(); void on_actClear_triggered(); void on_btnSend_clicked(); void on_actHostInfo_triggered(); private: Ui::MainWindow *ui; }; #endif // MAINWINDOW_H

mainwindow.cpp的实现

#include "mainwindow.h" #include "ui_mainwindow.h" #include QString MainWindow::getLocalIP() {//获取本机IPv4地址 QString hostName=QHostInfo::localHostName();//本地主机名 QHostInfo hostInfo=QHostInfo::fromName(hostName); QString localIP=""; QList addList=hostInfo.addresses();// if (!addList.isEmpty()) for (int i=0;iisListening()) tcpServer->close();;//停止网络监听 event->accept(); } MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); LabListen=new QLabel("监听状态:"); LabListen->setMinimumWidth(150); ui->statusBar->addWidget(LabListen); LabSocketState=new QLabel("Socket状态:");//状态栏信息 LabSocketState->setMinimumWidth(200); ui->statusBar->addWidget(LabSocketState); QString localIP=getLocalIP();//本机IP this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP); //设置标题 ui->comboIP->addItem(localIP); //创建QTcpServer实例 tcpServer,并将其newConnection()信号与onNewConnection()槽函数关联 tcpServer=new QTcpServer(this); connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection())); } MainWindow::~MainWindow() { delete ui; } //开始监听后,TCPClient就可以通过IP地址和端口连接到服务器,客户端接入时,tcpServe回发射newConnection()信号 //关联的槽函数onNewConnection()就会运行 void MainWindow::onNewConnection() { // ui->plainTextEdit->appendPlainText("有新连接"); tcpSocket = tcpServer->nextPendingConnection(); //创建socket connect(tcpSocket, SIGNAL(connected()), this, SLOT(onClientConnected())); onClientConnected();// connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected())); connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)), this,SLOT(onSocketStateChange(QAbstractSocket::SocketState))); onSocketStateChange(tcpSocket->state()); connect(tcpSocket,SIGNAL(readyRead()), this,SLOT(onSocketReadyRead())); } void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState) {//socket状态变化时 switch(socketState) { case QAbstractSocket::UnconnectedState: LabSocketState->setText("scoket状态:UnconnectedState"); break; case QAbstractSocket::HostLookupState: LabSocketState->setText("scoket状态:HostLookupState"); break; case QAbstractSocket::ConnectingState: LabSocketState->setText("scoket状态:ConnectingState"); break; case QAbstractSocket::ConnectedState: LabSocketState->setText("scoket状态:ConnectedState"); break; case QAbstractSocket::BoundState: LabSocketState->setText("scoket状态:BoundState"); break; case QAbstractSocket::ClosingState: LabSocketState->setText("scoket状态:ClosingState"); break; case QAbstractSocket::ListeningState: LabSocketState->setText("scoket状态:ListeningState"); } } void MainWindow::onClientConnected() {//客户端接入时,显示状态栏信息 ui->plainTextEdit->appendPlainText("**client socket connected"); ui->plainTextEdit->appendPlainText("**peer address:"+ tcpSocket->peerAddress().toString()); ui->plainTextEdit->appendPlainText("**peer port:"+ QString::number(tcpSocket->peerPort())); } void MainWindow::onClientDisconnected() {//客户端断开连接时 ui->plainTextEdit->appendPlainText("**client socket disconnected"); tcpSocket->deleteLater(); // deleteLater();//QObject::deleteLater(); } void MainWindow::onSocketReadyRead() {//读取缓冲区行文本 // QStringList lines; while(tcpSocket->canReadLine()) ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine()); // lines.append(clientConnection->readLine()); } void MainWindow::on_actStart_triggered() {//开始监听 QString IP=ui->comboIP->currentText();//IP地址 quint16 port=ui->spinPort->value();//端口 QHostAddress addr(IP); //作为服务器,QTcpServer类需要调用linsten()在本机某个IP地址和端口上开始监听,等待客户端接入 tcpServer->listen(addr,port);// // tcpServer->listen(QHostAddress::LocalHost,port);// Equivalent to QHostAddress("127.0.0.1"). ui->plainTextEdit->appendPlainText("**开始监听..."); ui->plainTextEdit->appendPlainText("**服务器地址:" +tcpServer->serverAddress().toString()); ui->plainTextEdit->appendPlainText("**服务器端口:" +QString::number(tcpServer->serverPort())); ui->actStart->setEnabled(false); ui->actStop->setEnabled(true); LabListen->setText("监听状态:正在监听"); } void MainWindow::on_actStop_triggered() {//停止监听 if (tcpServer->isListening()) //tcpServer正在监听 { tcpServer->close();//停止监听 ui->actStart->setEnabled(true); ui->actStop->setEnabled(false); LabListen->setText("监听状态:已停止监听"); } } void MainWindow::on_actClear_triggered() { ui->plainTextEdit->clear(); } void MainWindow::on_btnSend_clicked() {//发送一行字符串,以换行符结束 QString msg=ui->editMsg->text(); ui->plainTextEdit->appendPlainText("[out] "+msg); ui->editMsg->clear(); ui->editMsg->setFocus(); QByteArray str=msg.toUtf8(); str.append('\n');//添加一个换行符 tcpSocket->write(str); } void MainWindow::on_actHostInfo_triggered() {//获取本机地址 QString hostName=QHostInfo::localHostName();//本地主机名 ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n"); QHostInfo hostInfo=QHostInfo::fromName(hostName); QList addList=hostInfo.addresses();// if (!addList.isEmpty()) for (int i=0;iplainTextEdit->appendPlainText("本机IP地址:"+aHost.toString()); if (ui->comboIP->findText(IP)comboIP->addItem(IP); } } } QTcpServer的几个信号的作用

​ 1、connected()信号,客户端socket连接建立时发射此信号

​ 2、disconnected()信号,客户端socket连接断开时发射此信号

​ 3、stateChanged(),本程序的socket状态变化时发射此信号

​ 4、readyRead(),本程序的socket的读取缓冲区有新的数据时发射此信号

与TCPClient的数据通信

QTcpSocket类间接继承于QIODevice,所以支持流读写功能。

Socket之间的数据通信协议一般有两种方式:基于行、基于数据块。

基于块的数据通信协议

用于一般的数据的传输,需要自定义具体的格式

基于行的数据通信协议

一般用于纯文本数据的通信,每一行数据以一个换行符结束。canReadLine()函数判断是否有新的一行数据需要读取,再用readLine()函数读取一行数据。代码实现如下:

void MainWindow::onSocketReadyRead() {//读取缓冲区行文本 // QStringList lines; while(tcpSocket->canReadLine()) ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine()); // lines.append(clientConnection->readLine()); } 单击窗口上的“发送消息”,将文本框内容发送给客户端,代码实现如下 void MainWindow::on_btnSend_clicked() {//发送一行字符串,以换行符结束 QString msg=ui->editMsg->text(); ui->plainTextEdit->appendPlainText("[out] "+msg); ui->editMsg->clear(); ui->editMsg->setFocus(); QByteArray str=msg.toUtf8(); str.append('\n');//添加一个换行符 tcpSocket->write(str); }

从上面的代码可以知道,读取文本框字符串到msg后,先将其转换为QByteArray类型字节数组str,然后在str后添加一个换行符,用QIODevice的write()函数写入缓冲区。这样就可以给客户端发送一行数据了。

程序运行结果如图所示

在这里插入图片描述

客户端实现请跳转到:

https://blog.csdn.net/weixin_56169816/article/details/131404035?spm=1001.2014.3001.5501



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3