TCP通讯案例(保姆级教程)

不知道有么有小伙伴和我一样

明明教程已经很详细了

但是架不住菜的抠脚

在人家那里是孙红雷

下载下来自己一用就是马冬梅

于是我研究了一个网上的案例,把每一句话都写了注释

希望对和我一样菜的能有帮助

--只写保姆级教程--

(因为其他的也写不了~~!)

话不多说,上代码。

***----------****

首先TCP通讯,我们不想复杂了,因为我们是菜鸟。

我们想象打电话,是不是的一个打,一个接?

对,就是这个过程,所以我们需要两个端。

客户端和服务端。

Client端和Server端;

一:Client端代码:

--.h文件(里面我都做好了注释)

(只看cpp文件就行,从001开始)

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpSocket>
#include <QLabel>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:

    void on_sendMsg_clicked();

    void on_connect_clicked();

    void on_disconnect_clicked();

private:
    Ui::MainWindow *ui;
    QTcpSocket* c_tcp;
    //002--定义一个c_tcp监听对象;
    //002--在做这个定义之前,记得加上<QTcpSocket>的头文件;
    //这个就是创建一个Client(客户端)监听对象,我们简写为c_tcp;

    QTcpSocket* m_tcp;
    QLabel* m_status;
};
#endif // MAINWINDOW_H

--.cpp文件

//注释说明********崔某人********//

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

#include <QHostAddress>


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

    ui->port->setText("9527");
    ui->ip->setText("127.0.0.1");
    setWindowTitle("客户端");
    //001--把界面上的端口和IP,让它获取一个默认值;
    //001--更改一下窗口的名称;

    ui->disconnect->setDisabled(true);
    //002--去头文件内,定义一个监听对象;(---此处转头文件)
    // 创建监听的服务器对象
    c_tcp = new QTcpSocket;
    //003--创建监听对象
    //知识点:xxx = new xxx是个什么玩意?
    connect(c_tcp, &QTcpSocket::readyRead, this, [=]()
    {
         QByteArray data = c_tcp->readAll();
         ui->record->append("服务器say: " + data);
         //004--创建连接(信号和槽)
         //信号的发出者是我们定义的监听对象c_tcp,它发出了什么信号?readyRead(读取数据)
         //信号的接收者是this,接受了之后作何反应?(下面大括号的内容)
         //定义一个字节数组 data,然后把我们从---服务端---监听到的数据,read all(读取所有),放到data里面;
         //顺手把他放到UI界面上(append增加内容;record是控件的名称,可自主命名)

         //知识点:接收者this是个什么东西?
    });


    connect(c_tcp, &QTcpSocket::disconnected, this, [=]()
    {
        c_tcp->close();
        c_tcp->deleteLater();   // delete c_tcp
        m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20, 20));
        ui->record->append("服务器已经和客户端断开了连接...");
        ui->connect->setDisabled(false);
        ui->disconnect->setEnabled(false);
        //005--这个和004相对应的,关闭监听对象;
        //首先是个connect连接;
        //信号的发出者是c_tcp(还是我们的监听者;它发出的信号是disconnected;
        //接收者还是this;做出的反应见大括号内;

        //大括号内:
        //首先是 c_tcp close(关闭监听什么的)
        //然后是 c_tcp deleteLater  (关闭这个线程,这个描述不准确)
        //这个后面还加了个delete c_tcp  这个不推荐
        //deleteLater 是 QObject 类对象的成员函数,用于延迟删除一个 QObject 类对象;
        //deleteLater 会在当前对象的所有事件处理完成后再删除对象
        //delete 则是立即删除对象,对象的既有事件不再处理

        //接下来处理下状态栏m_status;
        //setPixmap 是让图片在控件上显示;
        //scaled(20, 20) 这个玩意是给我们需要显示的图片一个固定的尺寸;
        //这里需要注意,我们的先添加资源文件,而且":/disconnect.png"路径表述方式需要注意,免得找不到;

        //ui->record->append("服务器已经和客户端断开了连接...");
        //这一句,和之前一样,在历史消息里面加一句;(写到这里,应该注意一下append的用法了)
        //下面两句不明白
    });


    connect(c_tcp, &QTcpSocket::connected, this, [=](){
         m_status->setPixmap(QPixmap(":/connect.png").scaled(20, 20));
         ui->record->append("已经成功连接到了服务器...");
         ui->connect->setDisabled(true);
         ui->disconnect->setEnabled(true);
         //006--这个是连接成功的槽;
         //不做解释,和005基本一样,就是发出的信号不同;大括号内的内容稍有不同;

    });


    //007-- 状态栏
    m_status = new QLabel;
    m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20, 20));
    //这里让状态栏控件,默认获得连接失败的图标;
    ui->statusbar->addWidget(new QLabel("连接状态: "));
    ui->statusbar->addWidget(m_status);
    //这里给状态栏status再加上文本 label (注意和增加图片的不同)

}

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

void MainWindow::on_sendMsg_clicked()
{
    QString msg = ui->msg->toPlainText();
    c_tcp->write(msg.toUtf8());
    ui->record->append("客户端say: " + msg);
    //008--这个是当“发送信息”按钮被单击的槽函数;
    //首先是是使用下toPlainText()获取下文本内容,放到msg内;
    //接下来强行理解一波就行,我们这个按钮干嘛的?发送数据。
    //放到哪里发送呢?我们从头到尾就创建了一个对象,叫c_tcp,显然是放在这里面;
    //write是写入,写入什么?msg;以什么格式写入?utf8这个格式;
    //顺手把上面的历史消息更新一波;(这个其实就是单机版,不管是否连接了服务器,都能成功)
    //严谨点的话这个应该放在别的地方;不过问题不大;
}

void MainWindow::on_connect_clicked()
{
    QString ip = ui->ip->text();
    unsigned short port = ui->port->text().toUShort();
    c_tcp->connectToHost(QHostAddress(ip), port);
    //009--这个是连接服务器的按钮;
    //首先获取一下,IP那个控件内的内容;
    //这里要注意了,我们前面给了一个127.0.0.1;
    //所以实际去应用的时候,前面给不给无所谓;(或者直接填上你要给的那个就行)
    //接下来是获取端口号;
    //端口号前面的unsiged short 这个叫无符号短整型;(防止你有什么骚操作,或者不小心打错了)
    //最后也是最重要的一步,IP地址,端口号我们都正确的获取了,再干嘛?
    //肯定是和服务器连接一波;connect to host 是连接到主机;
    //这个函数里面有俩参数--IP地址和端口;
    //注意出现了个新的玩意儿,QHostAddress,在头文件要加上<QHostAddress>
    //当我们的IP地址和端口都正确的时候,就连接成功了(这么说不严谨,前提是那边开着)
}

void MainWindow::on_disconnect_clicked()
{
    c_tcp->close();
    ui->connect->setDisabled(false);
    ui->disconnect->setEnabled(false);
    //010--这个是关闭连接,没什么可解释的;
}
//*****Client端解释完毕,现在我们去Server端(Client序号是001--010)

二:客户端

--.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QLabel>


QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_setListen_clicked();

    void on_sendMsg_clicked();

private:
    Ui::MainWindow *ui;
    QTcpServer* m_s;
    QTcpSocket* s_tcp;
    
    QTcpSocket* m_tcp;
    QLabel* m_status;
};
#endif // MAINWINDOW_H

--.cpp文件

//注释说明********崔某人********//
//***先去看Client端**//
//Server端的序号从011开始//
#include "mainwindow.h"
#include "ui_mainwindow.h"


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

    ui->port->setText("9527");
    setWindowTitle("服务器");
    //011--使端口号默认获得一个端口;
    //011--更改一下窗口的标题;

    m_s = new QTcpServer(this);
    // 012--创建监听的服务器对象;
    //在Client端,我们创建的是c_tcp,是管着发送的;
    //那么对应的,我们需要创建一个用来监听的;
    //就像打电话一样,起码需要两部手机,一个打,一个接;这么理解;
    //
    connect(m_s, &QTcpServer::newConnection, this, [=](){
        s_tcp = m_s->nextPendingConnection();
        //013--注意看这个连接connect;
        //调用nextPendingConnection()来接受待处理的连接;我们的客户端,点击发送按钮之后,肯定发送了个连接请求;
        //nextPendingConnection这个就是用来处理请求;
        //剖析下这个连接;
        //信号的发出者是我们创建的服务端监听,它发出的信号是newConnection
        //可以把它理解为每当有新的连接可用时,都会发出此信号;
        //信号的接收者是this;接收者做出的反应是大括号内内容;

        m_status->setPixmap(QPixmap(":/connect.png").scaled(20, 20));
        //014--这一行不解释了,还是状态栏,只不过换了个图;
        connect(s_tcp, &QTcpSocket::readyRead, this, [=]()
        {
             QByteArray data = s_tcp->readAll();
             ui->record->append("客户端say: " + data);
        //015--这个也比较好理解;右这么几个点需要注意下:
        //首先,和Client端不一样的是,这个连接不是独立的,而是在上一个连接内,为什么?
        //(上面那个链接干嘛的?)(自己理解--结果就是,不显示客户端发送过来的内容)
        //第二点,还是剖析四件套--发出者,发出的信号,接收者,做出的反应;
        //发出者是s_tcp,信号是读取数据,接收者是this,反应是大括号内;
             //这个地方有点绕,顺一下:
             //首先s_tcp->readAll()  好理解,就是读取所有数据;
             //那么问题来了,s_tcp,里面有啥呀你就读?
             //往上翻我们发现了  s_tcp = m_s->nextPendingConnection();
             //咱们现在还在人家大连接里面呢,m_s->nextPendingConnection()是处理信号;
             //也就是说它瞎几把处理之后,赋值给了我们定义的s_tcp,然后读出来;
        //016--ui那个比较好理解;读取的内容显示到UI界面上;
   
        });
        connect(s_tcp, &QTcpSocket::disconnected, this, [=]()
        {
            s_tcp->close();
            s_tcp->deleteLater();   // delete s_tcp
            m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20, 20));
            //017--这个也好理解,关闭连接的,就是换个图;
        });

    });
   
    //018--不解释了,更改状态栏的一些操作;(有时间可以研究下里面的函数使用)
    m_status = new QLabel;

    m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20, 20));
    ui->statusbar->addWidget(new QLabel("连接状态: "));
    ui->statusbar->addWidget(m_status);

}

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


void MainWindow::on_setListen_clicked()
{
    unsigned short port = ui->port->text().toUShort();
    m_s->listen(QHostAddress::Any, port);
    ui->setListen->setDisabled(true);
    //019--这个是启动监听的按钮;
    //unsigned short port = ui->port->text().toUShort();这句话解释过了在Client端,不说了;
    //下面有新东西  m_s->listen(QHostAddress::Any, port);
    //m_s 是什么?是我们创建的监听啊!他要干嘛?
    //listen 监听;和我们Client端的那个发送很像;
    //还是别忘了加上<QHostAddress>的头文件;
    
}

void MainWindow::on_sendMsg_clicked()
{
    QString msg = ui->msg->toPlainText();
    s_tcp->write(msg.toUtf8());
    ui->record->append("服务器say: " + msg);
    //020--发送消息,和Client一样的不说了;
}


//总结:这个案例也有很多不足的地方,但是理解起来还是不错的;
//程序容易死掉,而且顺序不要错;
//总而言之还不错;

PS:效果图

先做UI界面,记好了控件的名称,免得到了代码里不认识 

猜你喜欢

转载自blog.csdn.net/BenBierBa/article/details/128555239