【QT】TCP

目录

核心API

示例:服务器和客户端信息互发

服务器代码实现

第一步:创建QTcpServer对象的实例

第二步:绑定信号槽,处理新的连接

第三步:绑定并监听端口号

客户端代码实现

第一步:创建socket对象的实例

第二步:和服务器建立连接

第三步:连接信号槽,处理响应 

第四步:等待连接结果,确认是否连接成功 

最终效果


UDP 无连接,不可靠传输,面向数据包,全双工

TCP 有连接,可靠传输,面向字节流,半双工

核心API

核心类是两个: QTcpServer QTcpSocket

QTcpServer ⽤于监听端⼝, 和获取客户端连接

名称
类型
说明
对标原⽣ API
listen(const QHostAddress&, quint16 port)
⽅法
绑定指定的地址和端⼝号, 并开始监听
bind 和 listen
nextPendingConnection()
⽅法
从系统中获取到⼀个已经建⽴好的 tcp 连接.
返回⼀个 QTcpSocket , 表⽰这个
客⼾端的连接.
通过这个 socket 对象完成和客⼾端 之间的通信
accept
newConnection
信号
有新的客⼾端建⽴连接好之后触发.
⽆ (但是类似于 IO 多路复⽤
中的通知机制)
QTcpSocket 用户客⼾端和服务器之间的数据交互
名称类型说明对标原⽣ API
readAll()
⽅法
读取当前接收缓冲区中的所有数据.
返回 QByteArray 对象.
read
write(const QByteArray& )
⽅法
把数据写⼊ socket 中.
write
deleteLater
⽅法
暂时把 socket 对象标记为⽆效. Qt
会在下个事件循环中析构释放该对
象.
⽆ (但是类似于 "半⾃动化的 垃圾回收")
readyRead
信号
有数据到达并准备就绪时触发
⽆ (但是类似于 IO 多路复⽤
中的通知机制)
disconnected
信号
连接断开时触发
⽆ (但是类似于 IO 多路复⽤
中的通知机制)

示例:服务器和客户端信息互发

服务器代码实现

首先区分QTcpServer 和 QTcpSocket,我们需要先使用QTcpServer来监听端⼝, 和获取客户端连接。

第一步:创建QTcpServer对象的实例

tcpServer = new QTcpServer(this代码);

第二步:绑定信号槽,处理新的连接

connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection);

processConnection方法 

void Widget::processConnection()

{

    //1.通过tcpserver拿到一个socket对象,通过这个对象来和客户端进行通信

    QTcpSocket* clientSocket = tcpServer->nextPendingConnection();

    QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端上线了!";

    ui->listWidget->addItem(log);

    //2.通过信号槽,来处理客户端发来请求的情况

    connect(clientSocket,&QTcpSocket::readyRead,this,[=](){

       // a) 读取请求数据,此处readAll返回的是QByteArray,通过赋值转成 QString

       QString request = clientSocket->readAll();

       // b) 根据请求处理响应

       const QString& response = process(request);

       // c) 把响应写回到客户端

       clientSocket->write(response.toUtf8());

       // d) 把上述信息记录到日志中

       QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "]" + "req:" + request + ",resp:" + response;

    });

       ui->listWidget->addItem(log);

    //3. 通过信号槽,来处理客户端断开连接的情况

    connect(clientSocket,&QTcpSocket::disconnected,this,[=](){

        //a) 把断开连接的信息通过日志显示出来

       QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端下线了!";

       ui->listWidget->addItem(log);

       //b) 手动释放clientSocket

       clientSocket->deleteLater();

    });

}

注意: 

  • 在Linux网络编程中,需要搞一个循环,循环的读取请求,循环的处理,在Qt中基于信号槽就不必循环了。每次客户端发来请求,都能触发readyRead信号。
  • 因为QTcpSocket是每个客户端都有一个这样的对象,存在n个,所以必须在客户端断开连接后手动释放,而QTcpServer和QUdpSocket只有一份
  • clientSocket->deleteLater();这个操作,不是立即销毁clientSocket,而是告诉Qt,下一轮事件循环时,再进行销毁操作。

第三步:绑定并监听端口号

    bool ret = tcpServer->listen(QHostAddress::Any,9090);

    if(!ret)

    {

        QMessageBox::critical(this,"服务器启动失败!",tcpServer->errorString());

        exit(1);

    }

完整代码:

widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

    void processConnection();
    QString process(const QString request);
private:
    Ui::Widget *ui;
    QTcpServer* tcpServer;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
#include <QTcpSocket>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);

    //修改窗口标题
    this->setWindowTitle("服务器");

    //2.创建QTcpServer的实例
    tcpServer = new QTcpServer(this);

    //3.通过信号槽,指定如何处理连接
    connect(tcpServer,&QTcpServer::newConnection,this,&Widget::processConnection);

    //4.绑定并监听端口号
    bool ret = tcpServer->listen(QHostAddress::Any,9090);
    if(!ret)
    {
        QMessageBox::critical(this,"服务器启动失败!",tcpServer->errorString());
        exit(1);
    }
}

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

void Widget::processConnection()
{
    //1.通过tcpserver拿到一个socket对象,通过这个对象来和客户端进行通信
    QTcpSocket* clientSocket = tcpServer->nextPendingConnection();
    QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端上线了!";
    ui->listWidget->addItem(log);

    //2.通过信号槽,来处理客户端发来请求的情况
    connect(clientSocket,&QTcpSocket::readyRead,this,[=](){
       // a) 读取请求数据,此处readAll返回的是QByteArray,通过赋值转成 QString
       QString request = clientSocket->readAll();
       // b) 根据请求处理响应
       const QString& response = process(request);
       // c) 把响应写回到客户端
       clientSocket->write(response.toUtf8());
       // d) 把上述信息记录到日志中
       QString log = "[" + clientSocket->peerAddress().toString() + ":" + QString::number(clientSocket->peerPort()) + "]" + "req:" + request + ",resp:" + response;
       ui->listWidget->addItem(log);
    });
       
    //3. 通过信号槽,来处理客户端断开连接的情况
    connect(clientSocket,&QTcpSocket::disconnected,this,[=](){
        //a) 把断开连接的信息通过日志显示出来
       QString log = "[" + clientSocket->peerAddress().toString() + ":" +QString::number(clientSocket->peerPort()) + " 客户端下线了!";
       ui->listWidget->addItem(log);
       //b) 手动释放clientSocket
       clientSocket->deleteLater();
    });
}

QString Widget::process(const QString request)
{
    return request;
}

客户端代码实现

客户端不需要跟服务器一样监听端口,因此只需要创建socket即可

第一步:创建socket对象的实例

 tcpSocket = new QTcpSocket(this);

第二步:和服务器建立连接

 这个函数不会阻塞等待三次握手完成的(非阻塞函数)

tcpSocket->connectToHost("127.0.0.1",9090);

第三步:连接信号槽,处理响应 

 connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){

       QString response = tcpSocket->readAll();

        ui->listWidget->addItem("服务器说:"+response);

    });

第四步:等待连接结果,确认是否连接成功 

    bool ret = tcpSocket->waitForConnected();

    if(!ret){

        QMessageBox::critical(this,"连接服务器",tcpSocket->errorString());

    }

完整代码: 

 widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpSocket>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT

public:
    Widget(QWidget *parent = nullptr);
    ~Widget();

private slots:
    void on_pushButton_clicked();

private:
    Ui::Widget *ui;
    QTcpSocket* tcpSocket;
};
#endif // WIDGET_H

widget.cpp

#include "widget.h"
#include "ui_widget.h"
#include <QMessageBox>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    //1.设置窗口标题
    this->setWindowTitle("客户端");

    //2.创建socket对象的实例
    tcpSocket = new QTcpSocket(this);

    //3.和服务器建立连接  这个函数不会阻塞等待三次握手完成的(非阻塞函数)
    tcpSocket->connectToHost("127.0.0.1",9090);

    //4. 连接信号槽,处理响应
    connect(tcpSocket,&QTcpSocket::readyRead,this,[=](){
       QString response = tcpSocket->readAll();
        ui->listWidget->addItem("服务器说:"+response);
    });

    //5.等待连接建立的结果,确认是否连接成功
    bool ret = tcpSocket->waitForConnected();
    if(!ret){
        QMessageBox::critical(this,"连接服务器",tcpSocket->errorString());
    }
}

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


void Widget::on_pushButton_clicked()
{
    //1.获取输入的内容
    const QString& text = ui->lineEdit->text();

    //2.发送数据给服务器
    tcpSocket->write(text.toUtf8());

    //3.把发送的信息显示到界面上
    ui->listWidget->addItem("客户端说:" + text);

    //4.清空输入框的内容
    ui->lineEdit->setText("");


}

最终效果

  • 24
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
05-26
Qt 是一个跨平台应用程序开发框架,其中包括了网络编程模块,可以实现 TCP 协议的网络通信。 在 Qt 中,可以通过 QTcpServer 和 QTcpSocket 类来实现 TCP 服务器和客户端的开发。 QTcpServer 类用于创建 TCP 服务器,可以监听并接受来自客户端的连接请求,并创建一个 QTcpSocket 对象来处理客户端与服务器之间的通信。 QTcpSocket 类用于创建 TCP 客户端,可以连接到指定的服务器并发送数据,同时可以接收服务器返回的数据。 下面是一个简单的 Qt TCP 服务器的示例代码: ```cpp #include <QTcpServer> #include <QTcpSocket> #include <QDebug> int main(int argc, char *argv[]) { QTcpServer server; if (!server.listen(QHostAddress::Any, 1234)) { qDebug() << "Failed to start server"; return 1; } qDebug() << "Server started"; while (true) { QTcpSocket *socket = server.nextPendingConnection(); if (!socket) continue; qDebug() << "Client connected"; socket->write("Hello, client\n"); socket->flush(); QByteArray data = socket->readAll(); qDebug() << "Received data: " << data; socket->close(); delete socket; } return 0; } ``` 这个示例代码创建了一个 TCP 服务器,并监听所有可用的网络接口的 1234 端口。当有客户端连接时,服务器会发送一条欢迎消息,并等待客户端发送数据。当客户端发送数据后,服务器会将数据打印到控制台,并关闭连接。 类似地,可以编写一个 TCP 客户端来连接到这个服务器并发送数据。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值