6、Qt笔记--TCP

版权声明:本文为博主原创文章,如要转载,请注明地址,谢谢^...^ https://blog.csdn.net/qq_38880380/article/details/79952082

一、TCP简介

1、TCP(Transmission Control Protocol 传输控制协议)是一种面向连接的、可靠的、基于字节流的传输层通信协议,由IETF的RFC 793定义。在简化的计算机网络OSI模型中,它完成第四层传输层所指定的功能,用户数据报协议(UDP)是同一层内另一个重要的传输协议。在因特网协议族(Internet protocol suite)中,TCP层是位于IP层之上,应用层之下的中间层。不同主机的应用层之间经常需要可靠的、像管道一样的连接,但是IP层不提供这样的流机制,而是提供不可靠的包交换。  

 

二、创建示例工程

1、流程分析

(1)客户端

//
客户端
1、创建QTcpSocket套接字对象
socket = new QTcpSocket();

2、使用这个对象连接服务器
socket->connectToHost(ip, port);

3、使用write函数向服务器发送数据
socket->write(data);

4、当socket接收缓冲区有新数据到来时,会发出readyRead()信号,因此为该信号添加槽函数以读取数据
connect(socket, SIGNAL(readyRead()), this, SLOT(socket_read_data()));

viod Client::socket_read_data()
{
	QByteArray buffer;
	//获取缓冲区数据
	buffer = socket->readAll();
}

5、断开与服务器的连接(注意close() 和 disconnectFromHost() 不同)
socket->disconnectFromHost();
//

(2)服务端

//
服务端
1、创建QTcpServer对象
server = new QTcpServer();

2、侦听一个端口,使得客户端可以使用这个端口访问服务器
server->listen(QHostAddress::Any, port);

3、当服务器被客户端访问时,会发出newConnection()信号,因此为该信号添加槽函数,并用一个QTcpSocket对象接收客户端访问
connect(server, SIGNAL(newConnection()), this, SLOT(server_new_connnect()));

void Server::server_new_connnect()
{
	//获取客户端连接
	socket = server->nextPendingConnection();
}

4、使用socket的write函数向客户端发送数据
socket->write(data);

5、当socket接收缓冲区有新数据到来时,会发出readyRead()信号,因此为该信号添加槽函数以读取数据
connect(socket, SIGNAL(readyRead()), this, SLOT(socket_read_data()));

viod Client::socket_read_data()
{
	QByteArray buffer;
	//获取缓冲区数据
	buffer = socket->readAll();
}

6、取消侦听
socket->close();
//

 

(3)图解过程

 

2、客户端程序

(1).pro文件中加上 network

//
QT       += network
//

(2)client.h头文件代码

//
#ifndef CLIENT_H
#define CLIENT_H

#include <QWidget>
#include <QTcpSocket>
#include <iostream>

namespace Ui {
class Client;
}

class Client : public QWidget
{
    Q_OBJECT

public:
    explicit Client(QWidget *parent = 0);
    ~Client();

private slots:
    void on_pb_connect_clicked();
    void on_pb_send_clicked();
    void socket_read_data();
    void socket_disconnected();

private:
    Ui::Client *ui;
    QTcpSocket *tcpSocket;
};

#endif // CLIENT_H
//

(3)client.cpp源文件代码

//
#include "client.h"
#include "ui_client.h"

Client::Client(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Client)
{
    ui->setupUi(this);
    tcpSocket = new QTcpSocket(this);

    //连接信号与槽
    connect(tcpSocket, &QTcpSocket::readyRead, this, &Client::socket_read_data);
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));

    ui->pb_send->setEnabled(false);
    ui->le_ip->setText("127.0.0.1");
    ui->le_port->setText("7654");
}

Client::~Client()
{
    delete this->tcpSocket;
    delete ui;
}

void Client::on_pb_connect_clicked()
{
    if(ui->pb_connect->text() == tr("连接"))
    {
        QString ip;
        int port;

        //获取IP地址
        ip = ui->le_ip->text();
        //获取端口号
        port = ui->le_port->text().toInt();

        //取消已有的连接
        tcpSocket->abort();
        //连接服务器
        tcpSocket->connectToHost(ip, port);

        //等待链接成功
        if(!tcpSocket->waitForConnected(30000))
        {
            std::cout << "connect error!" << std::endl;
            return;
        } else {
            std::cout << "connect success!" << std::endl;
        }

        //发送按键使能
        ui->pb_send->setEnabled(true);
        //修改按键文字
        ui->pb_connect->setText("断开连接");\

    } else {
        //断开连接
        tcpSocket->disconnectFromHost();
        //修改按键文字
        ui->pb_connect->setText("连接");
        ui->pb_send->setEnabled(false);
    }
}

void Client::on_pb_send_clicked()
{
    QString str = ui->te_send->toPlainText();
    qDebug() << str ;
    //获取文本框的内容并以ASCII码形式发送
    tcpSocket->write(ui->te_send->toPlainText().toLatin1());
    tcpSocket->flush();
}

void Client::socket_read_data()
{
    QByteArray buffer;
    //读取缓冲区数据
    buffer = tcpSocket->readAll();
    if(!buffer.isEmpty())
    {
        QString str = ui->te_receive->toPlainText();
        str += tr(buffer);
        //刷新显示
        ui->te_receive->setText(str);
    }
}

void Client::socket_disconnected()
{
    //发送按键失能
    ui->pb_send->setEnabled(false);
    //修改按键文字
    ui->pb_connect->setText("连接");
    std::cout << "Disconnected !" << std::endl;
}
//

3、服务端程序

(1).pro文件中加上 network

//
QT       += network
//

(2)server.h头文件代码

//
#ifndef SERVER_H
#define SERVER_H

#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <iostream>
#include <QDebug>

namespace Ui {
class Server;
}

class Server : public QWidget
{
    Q_OBJECT

public:
    explicit Server(QWidget *parent = 0);
    ~Server();

private slots:
    void on_pb_listen_clicked();
    void on_pb_send_clicked();
    void socket_read_data();
    void socket_disconnected();
    void server_new_connect();

private:
    Ui::Server *ui;
    QTcpServer *tcpServer;
    QTcpSocket *tcpSocket;
};

#endif // SERVER_H
//

(3)server.cpp源文件代码

//
#include "server.h"
#include "ui_server.h"

Server::Server(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Server)
{
    ui->setupUi(this);
    tcpServer = new QTcpServer(this);
    tcpSocket = new QTcpSocket(this);

    ui->le_port->setText("7654");
    ui->pb_send->setEnabled(false);

    //连接信号槽
    connect(tcpServer, SIGNAL(newConnection()), this, SLOT(server_new_connect()));

}

Server::~Server()
{
    tcpServer->close();
    tcpServer->deleteLater();
    delete ui;
}

void Server::on_pb_listen_clicked()
{
    if(ui->pb_listen->text() == tr("侦听"))
    {
        //从输入框获取端口号
        int port = ui->le_port->text().toInt();
        //监听指定的端口
        if(!tcpServer->listen(QHostAddress::Any, port))
        {
            //若出错,则输出错误信息
            qDebug() << tcpServer->errorString();
            return;
        }
        //修改按键文字
        ui->pb_listen->setText("取消侦听");
        qDebug() << "Listen success!";
    } else {
        //如果正在连接(点击侦听后立即取消侦听,若socket没有指定对象会有异常,应修正——2017.9.30)
        if(tcpSocket->state() == QAbstractSocket::ConnectedState)
        {
            //关闭连接
            tcpSocket->disconnectFromHost();
        }
        //取消侦听
        tcpServer->close();
        //修改按键文字
        ui->pb_listen->setText("侦听");
        //发送按键失能
        ui->pb_send->setEnabled(false);
    }
}

void Server::on_pb_send_clicked()
{
    qDebug() << "Send: " << ui->te_send->toPlainText();
    //获取文本框内容并以ASCII码形式发送
    tcpSocket->write(ui->te_send->toPlainText().toLatin1());
    tcpSocket->flush();
}

void Server::server_new_connect()
{
    //获取客户端连接
    tcpSocket = tcpServer->nextPendingConnection();
    //连接QTcpSocket的信号槽,以读取新数据
    connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(socket_read_data()));
    connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(socket_disconnected()));
    //发送按键使能
    ui->pb_send->setEnabled(true);

    qDebug() << "A Client connect!";
}

void Server::socket_read_data()
{
    QByteArray buffer;
    //读取缓冲区数据
    buffer = tcpSocket->readAll();
    if(!buffer.isEmpty())
    {
        QString str = ui->te_receive->toPlainText();
        str+=tr(buffer);
        //刷新显示
        ui->te_receive->setText(str);
    }
}

void Server::socket_disconnected()
{
    //发送按键失能
    ui->pb_send->setEnabled(false);
    qDebug() << "Disconnected!";
}
//

4、运行结果

5、工程代码

(1)工程分享

 

致谢

1、QT5实现简单的TCP通信

2、QT编写TCP入门+简单的实际项目(附源程序)

3、QTcpServer、QTcpSocket、QUdpSocket在聊天程序上的应用

 

 

 

阅读更多
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页