基于QT的TCP通信

一、linux下的tcp通信过程

其中bind绑定,会固定一个端口,否则是随机的。

一个链接是由双方的ip和端口组成的,固定端口保证源的不变性,

这样另一端在任何时候访问的目的都是一致的,也可以说这个端口提供了什么服务。

同时绑定后直接操作socket id就可以操作对应的链接了。

 

二、QT下的TCP通信过程

Qt中提供的所有的Socket类都是非阻塞的。

Qt中常用的用于socket通信的套接字类:

         QTcpServer

用于TCP/IP通信, 作为服务器端套接字使用

         QTcpSocket

用于TCP/IP通信,作为客户端套接字使用。

         QUdpSocket

用于UDP通信,服务器,客户端均使用此套接字。

 

1.QT下的服务端

1).socket函数变为QTcpServer

2).bind ,listen 统一为listen

同时没有accept,当有一个链接过来的时候,会产生一个信号:newconnection,可以从对应的槽函数中取出建立好的套接字(对方的)QTcpSocket

如果成功和对方建立好链接,通信套接字会自动触发connected信号

3).read :

对方发送数据过来,链接的套接字(通信套接字)就会触发(本机的)readyRead信号,需要在对应的槽函数中接收数据

4).write,

发送数据,对方的(客户端的)套接字(通信套接字)就会触发readyRead信号,需要在对应的槽函数中接收数据

如果对方主动断开连接,对方的(客户端的)套接字(通信套接字)会自动触发disconnected信号

2.QT下的客户端:

1).socket函数变为 QTcpSocket

2).connect变为connetToHost()

如果成功和对方建立好链接,就会自动触发connected信号

3).read :

对方发送数据过来,链接的套接字(通信套接字)就会触发(本机的)readyRead信号,需要在对应的槽函数中接收数据

4).write,

发送数据,对方的(服务器的)套接字(通信套接字)就会触发readyRead信号,需要在对应的槽函数中接收数据

如果对方主动断开连接,就会自动触发disconnected信号

具体见图《QtTCP通信过程》

 

#ifndef SERVERWIDGET_H
#define SERVERWIDGET_H

#include <QWidget>
#include <QTcpServer> //监听套接字
#include <QTcpSocket> //通信套接字

namespace Ui {
class ServerWidget;
}

class ServerWidget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_buttonSend_clicked();

    void on_buttonClose_clicked();

private:
    Ui::ServerWidget *ui;

    QTcpServer *tcpServer; //监听套接字
    QTcpSocket *tcpSocket; //通信套接字

};

#endif // SERVERWIDGET_H

serverwidget.h
#include "serverwidget.h"
#include "ui_serverwidget.h"

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

    tcpServer = NULL;
    tcpSocket = NULL;

    //监听套接字,指定父对象,让其自动回收空间
    tcpServer = new QTcpServer(this);

    tcpServer->listen(QHostAddress::Any, 8888);

    setWindowTitle("服务器: 8888");

    connect(tcpServer, &QTcpServer::newConnection,
            [=]()
            {
                //取出建立好连接的套接字
                tcpSocket = tcpServer->nextPendingConnection();

                //获取对方的IP和端口
                QString ip = tcpSocket->peerAddress().toString();
                qint16 port = tcpSocket->peerPort();
                QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);

                ui->textEditRead->setText(temp);

                connect(tcpSocket, &QTcpSocket::readyRead,
                        [=]()
                        {
                            //从通信套接字中取出内容
                            QByteArray array = tcpSocket->readAll();
                            ui->textEditRead->append(array);
                        }

                        );


            }

            );

}

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

void ServerWidget::on_buttonSend_clicked()
{
    if(NULL == tcpSocket)
    {
        return;
    }
    //获取编辑区内容
    QString str = ui->textEditWrite->toPlainText();
    //给对方发送数据, 使用套接字是tcpSocket
    tcpSocket->write( str.toUtf8().data() );

}

void ServerWidget::on_buttonClose_clicked()
{
    if(NULL == tcpSocket)
    {
        return;
    }

    //主动和客户端端口连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
    tcpSocket = NULL;
}

serverwidget.cpp
#ifndef CLIENTWIDGET_H
#define CLIENTWIDGET_H

#include <QWidget>
#include <QTcpSocket> //通信套接字

namespace Ui {
class ClientWidget;
}

class ClientWidget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_buttonConnect_clicked();

    void on_buttonSend_clicked();

    void on_buttonClose_clicked();

private:
    Ui::ClientWidget *ui;

    QTcpSocket *tcpSocket; //通信套接字
};

#endif // CLIENTWIDGET_H

clientwidget.h
#include "clientwidget.h"
#include "ui_clientwidget.h"
#include <QHostAddress>

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

    tcpSocket = NULL;

    //分配空间,指定父对象
    tcpSocket = new QTcpSocket(this);

    setWindowTitle("客户端");


    connect(tcpSocket, &QTcpSocket::connected,
            [=]()
            {
                ui->textEditRead->setText("成功和服务器建立好连接");
            }
            );

    connect(tcpSocket, &QTcpSocket::readyRead,
            [=]()
            {
                //获取对方发送的内容
                QByteArray array = tcpSocket->readAll();
                //追加到编辑区中
                ui->textEditRead->append(array);
            }

            );

}

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

void ClientWidget::on_buttonConnect_clicked()
{
    //获取服务器ip和端口
    QString ip = ui->lineEditIP->text();
    qint16 port = ui->lineEditPort->text().toInt();

    //主动和服务器建立连接
    tcpSocket->connectToHost(QHostAddress(ip), port);

}

void ClientWidget::on_buttonSend_clicked()
{
    //获取编辑框内容
    QString str = ui->textEditWrite->toPlainText();
    //发送数据
    tcpSocket->write( str.toUtf8().data() );

}

void ClientWidget::on_buttonClose_clicked()
{
    //主动和对方断开连接
    tcpSocket->disconnectFromHost();
    tcpSocket->close();
}

clientwidget.cpp

参考文章:https://www.cnblogs.com/yuweifeng/p/9382841.html

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值