Qt系列文章015-TCP客户端
1 前言
上一章主要讲述了服务端的程序设计,本章主要讲述客户端的程序设计和对应的通信交互,有了前面的基础,基本上下面的讲解,我想已经非常容易理解了!
2 客户端项目新建
还是老样子,先新建一个客户端的程序项目,如下图:
取名为TCPClient项目名称!新建工程完毕后,我们开始简单的界面设计,运行效果图如下:
客户端程序TCPClient只需要使用一个 QTcpSocket 对象,就可以和服务器端程序TcpServer 进行通信。
TCPClient也是一个窗口基于 QWidget 的应用程序,其主窗口的定义如下:
class TCPClient : public QWidget
{
Q_OBJECT
public:
TCPClient(QWidget *parent = nullptr);
~TCPClient();
//初始化数据和相关槽
void initDataSlot();
QString getLocalIP();
private slots:
//自定义槽函数
void onConnected() ;
void onDisconnected() ;
void onSocketStateChange(QAbstractSocket::SocketState socketState) ;
void onSocketReadyRead() ; //读取socket传入的数据
private:
Ui::TCPClient *ui;
QTcpSocket * mTcpClient = nullptr; //socket
bool misConnectService = false; //判断是否连接了服务器
};
这里只定义了一个用于socket 连接和通信的QTcpSocket变量mTcpClient ,自定义了几个槽函数, 用于与mTcpClient的相关信号关联。
下面是 TCPClient 的构造函数,主要功能是创建mTcpClient,初始化相关数据并建立信号与槽函数的关联。
TCPClient::TCPClient(QWidget *parent)
: QWidget(parent)
, ui(new Ui::TCPClient)
{
ui->setupUi(this);
initDataSlot();
}
void TCPClient::initDataSlot()
{
//创建Socket变量
if(mTcpClient == nullptr)
{
mTcpClient = new QTcpSocket(this);
}
//设置服务端的ip和端口
ui->lineEdit_serviceIP->setText(getLocalIP());
ui->lineEdit_servicePort->setText(QString::number(PORT));
misConnectService = false;
ui->label_socketState->setText("Socket 状态:");
//建立信号槽连接
connect(mTcpClient, &QTcpSocket::connected, this, &TCPClient::onConnected);
connect(mTcpClient, &QTcpSocket::disconnected, this, &TCPClient::onDisconnected);
connect(mTcpClient, &QTcpSocket::stateChanged, this, &TCPClient::onSocketStateChange);
connect(mTcpClient, &QTcpSocket::readyRead, this, &TCPClient::onSocketReadyRead);
}
QString TCPClient::getLocalIP()
{
//获取本机IPv4地址
QString hostName=QHostInfo::localHostName() ;//本地主机名
QHostInfo hostInfo=QHostInfo::fromName (hostName) ;
QString localIP="";
QList<QHostAddress> addList=hostInfo.addresses () ;
if (!addList. isEmpty())
{
for (int i=0; i <addList.count() ;i++)
{
QHostAddress aHost=addList.at(i) ;
if (QAbstractSocket::IPv4Protocol == aHost. protocol())
{
localIP=aHost. toString() ;
break;
}
}
}
return localIP;
}
3 与服务端建立连接
在窗口上设置服务器IP地址和端口后,调用QTepSocket的函数 connectToHost() 连接到服务器,也可以使用 disconnectFromHost() 函数断开与服务器的连接。
下面是上图中 连接服务器 按钮的响应代码,以及两个相关槽函数的代码:
void TCPClient::on_pushButton_connectService_clicked()
{
if(misConnectService)
{
misConnectService= false;
//断开服务器按钮
mTcpClient->disconnectFromHost();
ui->pushButton_connectService->setText("连接服务器");
}
else
{
misConnectService = true;
//连接服务器按钮
QString addr= ui->lineEdit_serviceIP->text();
quint16 port=ui->lineEdit_servicePort->text().toInt();
ui->pushButton_connectService->setText("断开服务器");
mTcpClient->connectToHost (addr,port) ;
}
}
void TCPClient::onConnected()
{
//connected()信号槽函数
ui->plainTextEdit->appendPlainText ("**已连接到服务器") ;
ui ->plainTextEdit->appendPlainText ("**peer address:"+ mTcpClient->peerAddress().toString()) ;
ui ->plainTextEdit->appendPlainText ("**peer port:"+ QString::number(mTcpClient->peerPort())) ;
}
槽函数onSocketStateChange( )的功能和代码与TcpServer 中的完全一样,如下代码:
void TCPClient::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
switch (socketState)
{
case QAbstractSocket::UnconnectedState:
ui->label_socketState->setText ("socket状态: UnconnectedState") ;
break;
case QAbstractSocket::HostLookupState:
ui->label_socketState->setText ("socket状态: HostLookupState") ;
break;
case QAbstractSocket::ConnectingState:
ui->label_socketState->setText ("socket状态: ConnectingState") ;
break;
case QAbstractSocket::ConnectedState:
ui->label_socketState->setText ("socket状态: ConnectedState") ;
break;
case QAbstractSocket::BoundState:
ui->label_socketState->setText ("socket状态: BoundState") ;
break;
case QAbstractSocket::ClosingState:
ui->label_socketState->setText ("socket状态: ClosingState") ;
break;
case QAbstractSocket::ListeningState:
ui->label_socketState->setText ("socket状态: ListeningState") ;
break;
}
}
4 与TCPServer的数据收发
TCPClient与TCPServer之间采用基于行的数据通信协议。单击上图中发送按钮将发送一行字符串。在 readyRead() 信号的槽函数里读取行字符串,其相关代码如下:
void TCPClient::on_pushButton_sendMsg_clicked()
{
//发送数据
QString msg=ui->lineEdit_msg->text() ;
ui->plainTextEdit->appendPlainText ("[out] "+msg) ;
ui->lineEdit_msg->clear() ;
ui->lineEdit_msg->setFocus() ;
QByteArray str=msg.toUtf8() ;
str.append('\n') ;
mTcpClient->write(str) ;
}
void TCPClient::onSocketReadyRead()
{
//readyRead()信号槽函数
while (mTcpClient->canReadLine())
{
ui->plainTextEdit->appendPlainText("[in] "+mTcpClient->readLine()) ;
}
}
5 交互动态演示
下面演示一下服务端和客户端的交互通信动态gif图如下:
6 总结
实例TCPServer和TCPClient只是简单演示了TCP通信的基本原理,TCPServer 只允许一个TCPClient客户端接入。而一般的TCP服务器程序允许多个客户端接入,为了使每个socket连接独立通信互不影响,一般采用多线程,即为一个socket连接创建一个线程。
实例TCPServer和TCPClient之间的数据通信采用基于行的通信协议,只能传输字符串数据。QTcpSocket间接继承于QIODevice,可以使用数据流的方式传输二进制数据流,例如传输图片、任意格式文件等,但是这涉及到服务器端和客户端之间通信协议的定义,这里不具体介绍了。
相关文章
- [Qt教程] 第30篇 XML(四)使用流读写XML
- Qt之自定义界面(实现无边框、可移动)
- qt 取进程列表,读写内存, 写字节集
- Qt编写的项目作品21-网络请求客户端/服务器
- Qt编写物联网管理平台49-设备模拟工具
- Qt编写地图综合应用4-仪表盘
- Qt系列文章003-第一个项目
- Qt怎么获取显示器分辨率
- Qt 读写txt文本文件
- Qt 断言Q_ASSERT的使用
- Qt OpenGL 加载3D世界,并在其中漫游
- Qt QMap简单用法
- Qt对象树机制
- Qt项目架构之一:全局类说明
- Qt自定义进度条
- Qt之实现工具箱界面程序
- C++中的stack类、QT中的QStack类
- QT 自定义Http客户端
- Qt编写的SMTP客户端(库)
- qt 中的自定义pushbutton