QT:Socket通讯(TCP) 学习笔记

环境:Qt Creator 5.9,7 

目录

1. 准备工作

2.服务器端 server项目

2.1  ui设计界面

2.2  .h文件代码

2.3  .cpp文件代码

3. 客户端 client项目

3.1  ui设计界面

3.2  .h文件代码

3.3  .cpp文件代码 

4. 测试演示

5.补充笔记


TCP服务端:
第一步:
创建监听套接字的QTcpSever

第二步:listen------监听是否有新的连接进来

第三步:取出套接字

第四步:读取套接字的内容


TCP客户端:
第一步:
创建套接字,与服务端的IP地址和端口号连接.(注:这里的端口号和上面服务端绑定的那个端口号是一样的,别搞错了.)

第二步:连接成功后就可以直接向服务端发消息了.

若要多次向服务端发消息,可以while循环或者是其他.在这里要注意如果要多次发消息的话,waitForBytesWritten()这个函数是必不可少的,不然多次的话可能通信会失败.

注:write()函数和被触发的读的readyRead()信号并不是一一对应的,比如可能你客户端write了三次,服务端那边的readyRead可能才被触发一次.

1. 准备工作

需创建两个project,一个服务器端 server,一个客户端 client。

服务器端 server: 

客户端 client:

注意: .pro文件记得添加

	QT       += network   //引用头文件 TcpServer 和 TcpSocket 的前提

 

2.服务器端 server项目

2.1  ui设计界面

2.2  .h文件代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QTcpServer>
#include <QTcpSocket>
#include <QString>


namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    QTcpServer *tcpserver; //第一步:创建监听套接字的QTcpSever
    QTcpSocket *tcpsocket;

private slots:
    void on_connectbt_clicked();

    void newConnection_Slot();
    void readyRead_Slot();

    void on_disconnectbt_clicked();

    void on_sendbt_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

2.3  .cpp文件代码

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

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

    tcpserver=new QTcpServer(this);
    tcpsocket=new QTcpSocket(this);

    //若有新的客户端连接的话,会触发信号newConnection_Slot()
    connect(tcpserver,SIGNAL(newConnection()),this,SLOT(newConnection_Slot()));
}


void MainWindow::newConnection_Slot()
{
    //第三步:取出套接字
    tcpsocket=tcpserver->nextPendingConnection(); //获取已经连接的客户端的SOCKET套接字
    connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));//若客户端有消息进来的话,会触发信号readyRead_Slot();

    //获取对方的IP和端口
    QString sIp = tcpsocket->peerAddress().toString();
    quint16 sPort = tcpsocket->peerPort();
    qDebug() << sIp << sPort;

    //connect(tcpsocket, SIGNAL(disconnected()), this, SLOT(slotServerDisConnection()));//断开连接的话会触发disconnected();
}
void MainWindow::readyRead_Slot()
{
    //第四步:读取套接字的内容
    //从socket中读出数据
     QString buf;
     buf=tcpsocket->readAll();
     ui->receivewd->appendPlainText(buf);

     /*或
     QByteArray baArray = tcpsocket->readAll();
     QString sMsg = baArray;
     ui->receivewd->appendPlainText(receivewd);
     */
}


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


void MainWindow::on_connectbt_clicked()//连接服务器
{
    //第二部步:listen------监听是否有新的连接进来
    tcpserver->listen(QHostAddress::Any,ui->portnum->text().toUInt());//监听端口号
}

void MainWindow::on_disconnectbt_clicked()//关闭服务器
{
    tcpserver->close();
}

void MainWindow::on_sendbt_clicked()//发送信息
{
//    toLatin1()
//    tcpsocket->write(ui->sendwd->text().toLatin1());
//    tcpsocket->write(ui->sendwd->text().toLocal8Bit(),ui->sendwd->text().length());
    tcpsocket->write(ui->sendwd->text().toLocal8Bit().data());
}

3. 客户端 client项目

3.1  ui设计界面

3.2  .h文件代码

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
//#include <QTcpServer>
#include <QTcpSocket>//服务端只用socket

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

    QTcpSocket *tcpsocket;

private slots:
    void on_openclient_clicked();

    void connected_SLOT();
    void readyRead_Slot();

    void on_closeclient_clicked();

    void on_sent_clicked();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

3.3  .cpp文件代码 

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "QString"
#include "stdio.h"

//#pragma execution_character_set("utf-8")

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

    tcpsocket=new QTcpSocket(this);
}

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



void MainWindow::connected_SLOT()
{
    QObject::connect(tcpsocket, &QTcpSocket::readyRead, this, &MainWindow::readyRead_Slot);
//    connect(tcpsocket,SIGNAL(readyRead()),this,SLOT(readyRead_Slot()));//将信号连接到槽,书写比较明确
}
void MainWindow::readyRead_Slot()//定义接收信号的槽
{
    QString buf;
    buf=tcpsocket->readAll();
    ui->receivewd->appendPlainText(buf);//接收由tcp发送过来的信息
//    ui->receivewd->appendPlainText(buf.toUtf8());//接收由tcp发送过来的信息
}


void MainWindow::on_openclient_clicked()
{
    //第一步:创建套接字,与服务端的IP地址和端口号连接.
    //注:这里的端口号和上面服务端绑定的那个端口号是一样的,别搞错了.
	//连接服务端
    tcpsocket->connectToHost(ui->ipnum->text(),ui->portnum->text().toInt());//转为无符号,连接服务器端口
    connect(tcpsocket,SIGNAL(connected()),this,SLOT(connected_SLOT()));
    printf("打开客户端 ");

    /*
    //成功连接返回true,错误返回false
    if(m_tsTcpSocket->waitForConnected())
    {
        qDebug() << "connect success";
    }
    */
}

void MainWindow::on_closeclient_clicked()
{
    tcpsocket->close();
    printf("关闭客户端 ");
}

void MainWindow::on_sent_clicked()
{
    tcpsocket->write(ui->sendwd->text().toLocal8Bit().data(),ui->sendwd->text().length());//丽丽
    //tcpsocket->write(ui->sendwd->text().toLocal8Bit().data());//网上
    //tcpsocket->write(ui->sendwd->toPlainText().toLatin1());//xie宏伟

    /*
	QString str;
	int iSize = tcpsocket->write(str.toUtf8().data());//返回字节的大小
    //等待write写完再写下一次的write
    if(!tcpsocket->waitForBytesWritten(50000))
    {
        return;
    }
    if(iSize ==-1) //判断发送是否成功
    {
        qDebug() << "write error";
        return;
    }
    若要多次向服务端发消息,可以while循环或者是其他.在这里要注意如果要多次发消息的
    话,waitForBytesWritten()这个函数是必不可少的,不然多次的话可能通信会失败.

    注:write()函数和被触发的读的readyRead()信号并不是一一对应的,比如可能你客户端
    write了三次,服务端那边的readyRead可能才被触发一次.
    */
}

主函数代码(两个工程皆相同):

#include "mainwindow.h"
#include <QApplication>
//#include <QtNetwork>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}

 补充:客户端主动断开服务的连接

void TcpClient::disConnectSever()
{
    //方式一
    m_tcpSocket->flush();
    m_tcpSocket->disconnectFromHost();
    
    //方式二
    m_tcpSocket->abort();
}

注:方式二abort与方式一的区别:abort中止当前连接并重置套接字。与disConnectFromHost()不同,该函数会立即关闭套接字,丢弃写缓冲区中的所有挂起数据。 

4. 测试演示

注意:

端口号须一致(端口号相当于房间号,进入同一房间后才可进行通讯)

服务器端须先点击 “ 连接服务器 ” 

客户端须先点击 “ 打开客户端 ” 

其次两者皆是输入内容再点击 “ 发送 ” 按钮

即可实现两者间的通讯

(暂不支持发送中文)

5.补充笔记

connect 函数:

connect(Sender,SIGNAL(signal),Receiver,SLOT(slot));  // 按键单击信号连接到按键槽函数

函数4个参数:发射信号的对象,发射的信号,接受信号的对象,要执行的槽;

详情:(3条消息) QT connect()连接函数_心若十年的博客-优快云博客_qt connect()

(以上学习笔记参考了(3条消息) qt中socket编程_真爱是蓝色的博客-优快云博客_qt socket

QT TCP简单的通信示例

拓展:

串口通信参考链接:QT三驾马车(一)——实现上位机(串口数据发送和接收)_qt上位机-优快云博客

### QTcpSocket 类使用方法 #### 基本概念 QTcpSocket 是 `QAbstractSocket` 的子类,专门用于创建 TCP 客户端套接字来建立 TCP 连接并传输数据流[^2]。 #### 创建和初始化 为了使用 QTcpSocket 实现一个简单的 TCP 客户端,首先需要实例化该对象。通常情况下会将其作为某个 QObject 对象的孩子传递给构造函数以便于管理生命周期: ```cpp QTcpSocket* socket = new QTcpSocket(parent); ``` 这里 parent 可以是任何继承自 QObject 的指针,比如窗口界面中的 widget 或者其他组件;如果不需要特定父级,则可以传入 nullptr。 #### 设置目标地址与端口 通过调用 setPeerName 和 setPeerPort 方法指定要连接的服务端 IP 地址以及监听端口号之前,应该先尝试直接利用 connectToHost 函数完成这两步操作: ```cpp socket->connectToHost("192.168.1.1", 12345); // 或者对于本地主机上的服务 socket->connectToHost(QHostAddress::LocalHost, 7756); ``` 上述代码片段展示了两种不同的方式去设置远程服务器的位置信息——既可以采用字符串形式表示 IPv4/IPv6 地址也可以借助 QHostAddress 枚举值简化书写过程[^3]。 #### 数据交互处理 当成功建立了到服务器的链接之后就可以开始收发消息了。每当有新的可读取的数据到达时就会触发 readyRead 信号,因此可以在槽函数内部执行具体的业务逻辑如接收响应内容等动作: ```cpp connect(socket, &QTcpSocket::readyRead, [](){ QByteArray data = socket->readAll(); qDebug() << "Received:" << QString(data); }); ``` 这段匿名 lambda 表达式的捕获列表为空意味着它不会捕捉外部变量而是依赖全局作用域下的名称解析机制找到合适的 socket 实例来进行 I/O 操作[^4]。 #### 断开连接后的清理工作 一旦完成了所有的通讯需求应当记得断开端点之间的关联以免造成资源浪费甚至潜在的安全风险。这可以通过 close 方法轻松达成目的: ```cpp if (socket && socket->state() != QAbstractSocket::UnconnectedState){ socket->close(); } delete socket; ``` 以上就是关于 QTcpSocket 类的一些常见应用场景及其对应的编码实践指南[^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值