Qt的TCP通信—客户端的实现

Qt的TCP通信—客户端的实现

客户端程序TCPClient只需要使用一个QTcpSocket对象,就可以和服务端程序TCPServer进行通信

服务端的实现流程

客户端的QTcpSocket首先通过connectToHost()尝试连接到服务器,需要指定服务器的IP地址和端口,connectToHost()是异步方式连接到服务器,不会阻塞程序运行,连接后发射connected()信号。

与服务器端建立socket连接后,就可以向缓冲区写数据或从接收缓冲区读取数据,实现数据的通信。当缓冲区有数据进入时,回发射readyRead()信号,一般在此信号的槽函数里读取缓冲区数据。

QTcpSocket是从QIODevice间接继承的,所以可以使用流数据读写功能。一个QTcpSocket既可以接收数据也可以发送数据,而且接收与发送是异步工作的,有各自的缓冲区。

客户端程序运行界面如图所示

在这里插入图片描述

实现功能:

​ 1、通过IP地址和端口号连接到服务器

​ 2、采用基于行的数据通信协议,于服务端收发数据

​ 3、处理QTcpSocket的StateChange()信号,在状态栏显示socket的状态

TCP客户端代码实现

mainwindow.h的实现

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include    <QTcpSocket>
#include    <QLabel>

namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QTcpSocket  *tcpClient;  //socket
    QLabel  *LabSocketState;  //状态栏显示标签

    QString getLocalIP();//获取本机IP地址
protected:
    void    closeEvent(QCloseEvent *event);
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void    onConnected();
    void    onDisconnected();
    void    onSocketStateChange(QAbstractSocket::SocketState socketState);
    void    onSocketReadyRead();//读取socket传入的数据

    void on_actConnect_triggered();
    void on_actDisconnect_triggered();
    void on_actClear_triggered();
    void on_btnSend_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

mainwindow.cpp的实现

#include "mainwindow.h"
#include "ui_mainwindow.h"

#include    <QHostAddress>
#include    <QHostInfo>

QString MainWindow::getLocalIP()
{
    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;
}
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
    event->accept();
}

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    tcpClient=new QTcpSocket(this); //创建socket变量

    LabSocketState=new QLabel("Socket状态:");//状态栏标签
    LabSocketState->setMinimumWidth(250);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    ui->comboServer->addItem(localIP);


    connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));
    //获取连接状态
    connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
            this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    connect(tcpClient,SIGNAL(readyRead()),
            this,SLOT(onSocketReadyRead()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onConnected()
{ //connected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已连接到服务器");
    ui->plainTextEdit->appendPlainText("**peer address:"+
                                       tcpClient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+
                                       QString::number(tcpClient->peerPort()));
    ui->actConnect->setEnabled(false);
    ui->actDisconnect->setEnabled(true);
}

void MainWindow::onDisconnected()
{//disConnected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    ui->actConnect->setEnabled(true);
    ui->actDisconnect->setEnabled(false);
}

void MainWindow::onSocketReadyRead()
{//readyRead()信号槽函数
    while(tcpClient->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号槽函数
    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::on_actConnect_triggered()
{//连接到服务器
    QString     addr=ui->comboServer->currentText();
    quint16     port=ui->spinPort->value();
    tcpClient->connectToHost(addr,port);
    //    tcpClient->connectToHost(QHostAddress::LocalHost,port);
}

void MainWindow::on_actDisconnect_triggered()
{//断开与服务器的连接
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
}

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');
    tcpClient->write(str);
}

程序运行结果如图所示

在这里插入图片描述

总结

服务器和客户端的实现只是简单的演示了TCP通信的基本原理,TCPServer只允许一个TCPClient客户端接入。而一般的TCP服务器程序允许多个客户端接入。为了使每个socket连接独立通信不影响,一般采用多线程,既为一个socket连接创建一个线程

lient->write(str);
}


#### 程序运行结果如图所示

[外链图片转存中...(img-ldEvMlvq-1687778801285)]

### 总结

服务器和客户端的实现只是简单的演示了TCP通信的基本原理,TCPServer只允许一个TCPClient客户端接入。而一般的TCP服务器程序允许多个客户端接入。为了使每个socket连接独立通信不影响,一般采用多线程,既为一个socket连接创建一个线程

以上实例之间的数据通信采用基于行的数据通信协议,只能传输字符串数据。QTcpSocket间接继承QIODevice,可以使用数据流的方式传输二进制数据流,列如传输图片、任意格式文件等。但是这涉及到服务端和客户端之间通信协议的定义。
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!以下是一个简单的C++ Qt TCP通信客户端和服务端代码示例: 服务端代码: ```cpp #include <QTcpServer> #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTcpServer server; server.listen(QHostAddress::Any, 1234); // 监听所有地址的1234端口 QObject::connect(&server, &QTcpServer::newConnection, [&]() { QTcpSocket *socket = server.nextPendingConnection(); QObject::connect(socket, &QTcpSocket::readyRead, [&]() { QByteArray data = socket->readAll(); qDebug() << "接收到客户端消息:" << data; socket->write("服务器已接收到消息"); socket->flush(); }); }); return a.exec(); } ``` 客户端代码: ```cpp #include <QTcpSocket> int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); QTcpSocket socket; socket.connectToHost("localhost", 1234); // 连接到本地主机的1234端口 QObject::connect(&socket, &QTcpSocket::connected, [&]() { qDebug() << "已连接到服务器"; socket.write("Hello Server"); socket.flush(); }); QObject::connect(&socket, &QTcpSocket::readyRead, [&]() { QByteArray data = socket.readAll(); qDebug() << "接收到服务器消息:" << data; socket.close(); }); return a.exec(); } ``` 这个示例中,服务端监听在1234端口,客户端连接到本地主机的1234端口。当客户端连接成功后,客户端会发送"Hello Server"的消息给服务端,服务端接收到消息后会回复"服务器已接收到消息"给客户端客户端接收到回复后会打印出来并关闭连接。 你可以根据需要修改代码来满足你的具体需求。希望对你有帮助!如有其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值