Qt Tcp网络编程

2 篇文章 1 订阅
本文介绍了QTcpSocket和QTcpServer在QT库中如何用于实现TCP通信。QTcpSocket用于客户端,通过‘三次握手’建立连接,提供可靠服务,支持点对点传输。QTcpServer则用于服务端,监听并处理连接请求。代码示例展示了如何创建和管理套接字,包括连接、断开、数据发送和接收以及错误处理。
摘要由CSDN通过智能技术生成

概念

TCP/IP协议在一定程度上参考了OSI的体系结构。OSI模型共有七层,从下到上分别是物理层、数据链路层、网络层、运输层、会话层、表示层和应用层。但是这显然是有些复杂的,所以在TCP/IP协议中,它们被简化为了四个层次。来自百度

Tcp通信的特点

1 面向连接:是指发送数据之前必须在两端建立连接,“三次握手”
2.提供可靠的服务:Tcp通过校验和,使用重传控制、流量控制和拥塞控制
3.每条传输连接只能有两个端点,只能进行点对点的数据传输,不支持多播和广播传输方式
4…面向字节流
套接字(socket)是通信的基石,是支持TCP/IP协议的网络通信的基本操作单元。它是网络通信过程中端点的抽象表示,包含进行网络通信必须的五种信息:连接使用的协议,本地主机的IP地址,本地进程的协议端口,远地主机的IP地址,远地进程的协议端口。
套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。

效果

在这里插入图片描述

QT提供了QTcpSocket类,可以方便的实现一个客户端;
.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_btnClearRec_clicked();

    //接受数据
    void receiveData();

    //处理错误信息
    void ReadError(QAbstractSocket::SocketError);

    void on_btn_Connect_clicked();

    void on_btn_DisConnect_clicked();

    void on_btnSend_clicked();

private:
    Ui::Widget *ui;
    //套接字    
    QTcpSocket *m_Socket = nullptr;


};
#endif // WIDGET_H

.cpp

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

    ui->btn_DisConnect->setEnabled(false);

    m_Socket = new QTcpSocket(this);

    //设置代理模式
    m_Socket->setProxy(QNetworkProxy::NoProxy);

    //读取新数据信号槽
    connect(m_Socket, SIGNAL(readyRead()), this, SLOT(receiveData()));

    //连接错误信息信号槽
    connect(m_Socket, SIGNAL(error(QAbstractSocket::SocketError)),
            this, SLOT(ReadError(QAbstractSocket::SocketError)));

    //调用connectToHost()并成功建立连接之后发出此信号。
    connect(m_Socket, &QTcpSocket::connected,[&]{
        ui->textEdit_Receive->append(QStringLiteral("连接成功"));
    });

    //当套接字断开连接时发出此信号
    connect(m_Socket, &QTcpSocket::disconnected,[&]{
        ui->textEdit_Receive->append(QStringLiteral("断开连接"));
    });


}

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


void Widget::on_btnClearRec_clicked()
{
    ui->textEdit_Receive->clear();
}

void Widget::receiveData()
{
    QByteArray buffer = m_Socket->readAll();
    if(!buffer.isEmpty())
    {
       ui->textEdit_Receive->append(buffer);
    }
}

void Widget::ReadError(QAbstractSocket::SocketError)
{
    m_Socket->disconnectFromHost();
    ui->textEdit_Receive->append(m_Socket->errorString());
}

void Widget::on_btn_Connect_clicked()
{
    //连接服务器
    m_Socket->connectToHost(ui->lineEditI_Ip->text(), ui->lineEdit_Port->text().toInt());
    if (m_Socket->waitForConnected(1000))
    {
        ui->btn_Connect->setEnabled(false);
        ui->btn_DisConnect->setEnabled(true);

    }
}

void Widget::on_btn_DisConnect_clicked()
{
    //断开连接
    m_Socket->disconnectFromHost();
    if (m_Socket->state() == QAbstractSocket::UnconnectedState
         || m_Socket->waitForDisconnected(1000))
    {
     ui->btn_Connect->setEnabled(true);
     ui->btn_DisConnect->setEnabled(false);
    }
}

void Widget::on_btnSend_clicked()
{
    QString data = ui->textEdit_Send->toPlainText();
    if(data != "")
    {
        //发送数据
        m_Socket->write(data.toLatin1());
    }
}

QT提供了QTcpServer类,可以方便的实现一个服务端;
.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QNetworkInterface>
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 receiveData();

    void on_btn_Connect_clicked();

    void on_btn_DisConnect_clicked();

    void on_btnSend_clicked();

private:
    Ui::Widget *ui;
    //服务器
    QTcpServer *m_tcpServer = nullptr;
    
    //套接字
    QTcpSocket *m_tcpSocket = nullptr;

};
#endif // WIDGET_H

.cpp文件

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

    m_tcpServer = new QTcpServer(this);
    m_tcpSocket = new QTcpSocket(this);
    
    //设置代理模式
    m_tcpSocket->setProxy(QNetworkProxy::NoProxy);

    //每当有新的连接可用时,就会发出此信号。
    connect(m_tcpServer, &QTcpServer::newConnection, this,[&]{
        m_tcpSocket = m_tcpServer->nextPendingConnection();
        
    //该信号在设备当前读取通道中每次有新的数据可用时发出。
    connect(m_tcpSocket, &QTcpSocket::readyRead, this, &Widget::receiveData);
    
    //当套接字断开连接时发出此信号。
    connect(m_tcpSocket, &QTcpSocket::disconnected,this,[&]{
            ui->textEdit_Rec->append(QStringLiteral("断开连接"));
        });
    });
    
    //获取本地IP
    ui->lineEditI_Ip->setText(QNetworkInterface().allAddresses().at(1).toString());   
}

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

void Widget::receiveData()
{
     //从设备读取所有剩余的数据,并将其作为字节数组返回。
     QByteArray buffer = m_tcpSocket->readAll();
     ui->textEdit_Rec->append(buffer);
}

void Widget::on_btn_Connect_clicked()
{
    //服务器监听传入的连接。当port为0时,
    //系统自动选择端口。如果address为QHostAddress::Any,服务器将监听所有网络接口。
    bool ok = m_tcpServer->listen(QHostAddress::Any, ui->lineEdit_Port->text().toInt());
    if(ok)
    {
        ui->btn_Connect->setEnabled(false);
        ui->btn_DisConnect->setEnabled(true);
    }
}

void Widget::on_btn_DisConnect_clicked()
{
    //关闭socket
    m_tcpSocket->disconnectFromHost();
    
    //等待直到套接字断开连接。
    //如果连接已经断开,这个函数返回true;否则返回false。
    bool ok = m_tcpSocket->waitForDisconnected(1000);
    
    ui->btn_DisConnect->setEnabled(false);
    ui->btn_Connect->setEnabled(true);
    
    //不再监听端口
    m_tcpServer->close();     
    m_tcpSocket->destroyed();
}

void Widget::on_btnSend_clicked()
{
    QString data = ui->textEdit_Send->toPlainText();
    if(data != "")
    {
        //发送数据
        m_tcpSocket->write(data.toLatin1());
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值