基于QT的TCP通信实现(TCPServer和TCPClient)

3 篇文章 1 订阅
1 篇文章 0 订阅


近期因为测试需要用到 TCPServer(TCP服务端)TCPClient(TCP客户端)来进行通信和数据的发送以及接受,所以用QT分别写了TCP服务端和TCP客户端,本文分享以下基于QT开发TCPServer和TCPClient的经验, 文中包括源码,在文末处包含项目的源码文件

一、软件介绍

TCPServer可以绑定一个ip地址并监听一个端口,在TCPServer绑定并监听状态时,可以使用TCPClient来连接服务端绑定的ip地址和端口,连接成功后便可进行通信了。下面首先演示以下服务端和客户端界面以及通信流程。

1.1 TCPServer服务端界面

  • 在服务端的界面中,“开始监听”按钮可以在设置“监听地址”、“监听端口”后点击既开始对此ip地址和端口进行监听,当有TCPClient客户端针对此ip地址和端口进行请求连接时便可进行连接,随后开始通信。
  • “停止监听”可以停止对ip地址和端口号的监听。
  • “清空文本框”按钮可以清空消息记录,方便连续信息的阅读。
  • “退出”按钮即关闭此软件。
  • “发送消息”可发送已经输入的内容。
    在这里插入图片描述

1.2 TCPClient客户端界面

  • 在客户端的界面中,“连接”按钮可以在设置“连接地址”、“端口”后点击既开始对此ip地址和端口进行请求连接,当有TCPServer服务端针对此ip地址和端口进行监听时便可进行连接,随后开始通信。
  • “断开连接”可以讲服务端和客户端已经建立的连接断开。
  • “清空文本框”按钮可以清空消息记录,方便连续信息的阅读。
  • “发送消息”和“清除”按钮分别可发送和清除已经输入的内容。
  • “退出”按钮即关闭此软件。
    在这里插入图片描述

1.3 服务端和客户端建立连接并通信演示

  • 首先在Server端我们绑定ip:192.168.31.222,端口:1200,然后点击“开始监听”按钮,这时服务端就开始等待Client端请求建立连接。
    在这里插入图片描述
  • 接下来我们使用客户端,连接地址和端口号设置为服务端所绑定的ip:192.168.31.222,端口:1200,然后点击“连接”按钮,可以看到双方建立连接成功,软件出现连接成功建立提示信息。
    在这里插入图片描述
  • 双方建立连接成功便可以开始通信,我们首先点击“清空文本框”把提示信息清除,然后使用TCPServer服务端发送一条信息“Hello,I’m TCPServer~”,可以看到客户端成功收到服务端发送的信息,[in]后边的内容为本端收到的信息,[out]后边的内容为本端发送的信息。
    在这里插入图片描述
  • 接下来我们使用TCPClient客户端给服务端发送一条信息“Hi,I’m TCPClient!”,可以看到服务端成功收到信息。
    在这里插入图片描述

二、QT实现TCPServer和TCPClient

我们想要在QT中实现TCP通信需要在.pro文件中添加下面一行代码:

QT       += network

2.1 TCPClient客户端

  • 首先我们应该包含下面三个头文件来支持我们调用内部的通信函数:
#include <QTcpSocket>
#include <QHostAddress>
#include <QHostInfo>
  • 创建QTcpSocket套接字对象
tcpClient = new QTcpSocket(this);
  • 使用tcpClient 对象连接服务器
tcpClient ->connectToHost(IP, port);
  • 然后我们用write()函数向服务器发送数据
tcpClient ->write(data);
  • 当tcpClient 接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据
connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

void MainWindow::onSocketReadyRead()
{//readyRead()信号槽函数
    while(tcpClient->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}
  • 在我们通信完毕后需要断开连接
void MainWindow::on_actDisconnect_triggered()
{//断开与服务器的连接
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
}

下面给出TCPClient的代码

  • main.cpp
#include "mainwindow.h"
#include <QApplication>
#include <QFile>

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

    return a.exec();
}

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
private:
    QTcpSocket *tcpClient;  //socket
    QLabel *LabSocketState;  //状态栏显示标签

    QString getLocalIP();//获取本机IP地址
protected:
    void closeEvent(QCloseEvent *event);
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
//自定义槽函数
    void onConnected();
    void onDisconnected();
    void onSocketStateChange(QAbstractSocket::SocketState socketState);
    void onSocketReadyRead();//读取socket传入的数据

    void on_actConnect_triggered();
    void on_actDisconnect_triggered();
    void on_actClear_triggered();
    void on_btnSend_clicked();
    void on_btnClear_clicked();
    void on_actionTimeCurrent_triggered();

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H

  • mainwindow.cpp
#pragma execution_character_set("utf-8")
#include "mainwindow.h"
#include "ui_mainwindow.h"

#include <QHostAddress>
#include <QHostInfo>
#include <QDateTime>

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

    tcpClient = new QTcpSocket(this); //创建socket变量

    LabSocketState = new QLabel("Socket状态:");//状态栏标签
    LabSocketState->setMinimumWidth(250);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle("TCP客户端");
    ui->comboServer->addItem(localIP);

    setFocusPolicy(Qt::StrongFocus);
    installEventFilter(this); 

    connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnected()));
    connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnected()));

    connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}

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

void MainWindow::onConnected()
{ //connected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已连接到服务器");
    ui->plainTextEdit->appendPlainText("**peer address:"+tcpClient->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpClient->peerPort()));
    ui->actConnect->setEnabled(false);
    ui->actDisconnect->setEnabled(true);
}

QString MainWindow::getLocalIP()
{
    QString hostName = QHostInfo::localHostName();//本地主机名
    QHostInfo hostInfo = QHostInfo::fromName(hostName);
    QString localIP = "";

    QList<QHostAddress> addList=hostInfo.addresses();

    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost = addList.at(i);
        if (QAbstractSocket::IPv4Protocol == aHost.protocol())
        {
            localIP=aHost.toString();
            break;
        }
    }
    return localIP;
}
void MainWindow::closeEvent(QCloseEvent *event)
{
    if (tcpClient->state() == QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
    event->accept();
}

void MainWindow::onDisconnected()
{//disConnected()信号槽函数
    ui->plainTextEdit->appendPlainText("**已断开与服务器的连接");
    ui->actConnect->setEnabled(true);
    ui->actDisconnect->setEnabled(false);
}

void MainWindow::onSocketReadyRead()
{//readyRead()信号槽函数
    while(tcpClient->canReadLine())
        ui->plainTextEdit->appendPlainText("[in] "+tcpClient->readLine());
}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//stateChange()信号槽函数
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;

    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;

    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;

    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;

    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void MainWindow::on_actConnect_triggered()
{//连接到服务器
    QString addr=ui->comboServer->currentText();
    quint16 port=ui->spinPort->value();
    tcpClient->connectToHost(addr,port);
}

void MainWindow::on_actDisconnect_triggered()
{//断开与服务器的连接
    if (tcpClient->state()==QAbstractSocket::ConnectedState)
        tcpClient->disconnectFromHost();
}

void MainWindow::on_actClear_triggered()
{
    ui->plainTextEdit->clear();
}

void MainWindow::on_btnSend_clicked()
{//发送数据

    QString msg=ui->editMsg->toPlainText();
    ui->plainTextEdit->appendPlainText("[out] "+msg);

    ui->editMsg->setFocus();

    QByteArray str = msg.toLatin1();
    str.append("\r\n");
    tcpClient->write(str);
}

void MainWindow::on_btnClear_clicked()
{
    ui->editMsg->clear();
}

void MainWindow::on_actionTimeCurrent_triggered()
{
    QString msg=QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz");
    ui->plainTextEdit->appendPlainText(+" [out] "+msg);

    ui->editMsg->setFocus();

    QByteArray str = msg.toLatin1();
    str.append("\r\n\r\n");
    tcpClient->write(str);
}

  • ui界面
    在这里插入图片描述

2.1 TCPServer服务端

  • 首先需要包含下面的头文件来提供我们需要调用的函数:
#include <QTcpServer>
#include <QtNetwork>
  • 然后创建TCPServer对象
tcpServer=new QTcpServer(this);
  • 绑定ip并监听端口功能,为客户端可以通过这个端口访问服务器
tcpServer->listen(addr,port);
  • 当tcpServer被tcpClient访问时,会发出newConnection()信号,因此为该信号添加槽函数,并用一个QTcpSocket对象接受客户端访问
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));

void MainWindow::onNewConnection()
{
    tcpSocket = tcpServer->nextPendingConnection(); //创建socket

    connect(tcpSocket, SIGNAL(connected()),this, SLOT(onClientConnected()));
    onClientConnected();
    connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(onClientDisconnected()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(tcpSocket->state());
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}
  • 使用tcpSocket的write()函数向客户端发送数据
tcpSocket->write(data);
  • 当tcpSocket接收缓冲区有新数据到来时,会发出readRead()信号,因此为该信号添加槽函数以读取数据
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));

void MainWindow::onSocketReadyRead()
{
    while(tcpSocket->canReadLine()){
        ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
    }
}
  • 停止监听
void MainWindow::on_actStop_triggered()
{
    if (tcpServer->isListening()) //tcpServer正在监听
    {
        tcpServer->close();//停止监听
        ui->actStart->setEnabled(true);
        ui->actStop->setEnabled(false);
        LabListen->setText("监听状态:已停止监听");
    }
}

下面给出TCPServer的代码

  • main.cpp
#include "mainwindow.h"
#include <QApplication>

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

    return a.exec();
}

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

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

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

protected:
    void closeEvent(QCloseEvent *event);//关闭窗口时停止监听

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

private slots:
    void onNewConnection();//QTcpServer的newConnection()信号
    void onSocketStateChange(QAbstractSocket::SocketState socketState);//底部socket状态变化
    void onClientConnected(); //客户端接入时
    void onClientDisconnected();//客户端断开连接时
    void onSocketReadyRead();//读取socket传入的数据

    void on_actStart_triggered();//开始监听
    void on_actStop_triggered();//停止监听
    void on_actClear_triggered();//清空
    void on_btnSend_clicked();//发送消息
    void on_actHostInfo_triggered();//获取本机地址

private:
    Ui::MainWindow *ui;
    QLabel *LabListen;//状态栏标签
    QLabel *LabSocketState;//状态栏标签
    QTcpServer *tcpServer; //TCP服务器
    QTcpSocket *tcpSocket;//TCP通讯的Socket
    QString getLocalIP();//获取本机IP地址
};

#endif // MAINWINDOW_H

  • mainwindow.cpp
#pragma execution_character_set("utf-8")
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QtNetwork>

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

    LabListen=new QLabel("监听状态:");
    LabListen->setMinimumWidth(150);
    ui->statusBar->addWidget(LabListen);

    LabSocketState=new QLabel("Socket状态:");
    LabSocketState->setMinimumWidth(200);
    ui->statusBar->addWidget(LabSocketState);

    QString localIP=getLocalIP();//本机IP
    this->setWindowTitle(this->windowTitle()+"----本机IP:"+localIP);
    ui->comboIP->addItem(localIP);

    tcpServer=new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}

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

QString MainWindow::getLocalIP()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    QHostInfo hostInfo=QHostInfo::fromName(hostName);
    QString localIP="";

    QList<QHostAddress> addList=hostInfo.addresses();

    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            localIP=aHost.toString();
            break;
        }
    }
    return localIP;
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    if (tcpServer->isListening())
        tcpServer->close();//停止网络监听
    event->accept();
}

void MainWindow::onNewConnection()
{
    tcpSocket = tcpServer->nextPendingConnection(); //创建socket

    connect(tcpSocket, SIGNAL(connected()),this, SLOT(onClientConnected()));
    onClientConnected();
    connect(tcpSocket, SIGNAL(disconnected()),this, SLOT(onClientDisconnected()));
    connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
    onSocketStateChange(tcpSocket->state());
    connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
}

void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState)
{
    qDebug()<<"走到这了";
    switch(socketState)
    {
    case QAbstractSocket::UnconnectedState:
        LabSocketState->setText("scoket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        LabSocketState->setText("scoket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        LabSocketState->setText("scoket状态:ConnectingState");
        break;
    case QAbstractSocket::ConnectedState:
        LabSocketState->setText("scoket状态:ConnectedState");
        break;
    case QAbstractSocket::BoundState:
        LabSocketState->setText("scoket状态:BoundState");
        break;
    case QAbstractSocket::ClosingState:
        LabSocketState->setText("scoket状态:ClosingState");
        break;
    case QAbstractSocket::ListeningState:
        LabSocketState->setText("scoket状态:ListeningState");
    }
}

void MainWindow::onClientConnected()
{
    ui->plainTextEdit->appendPlainText("**client socket connected");
    ui->plainTextEdit->appendPlainText("**peer address:"+tcpSocket->peerAddress().toString());
    ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpSocket->peerPort()));
}

void MainWindow::onClientDisconnected()
{
    ui->plainTextEdit->appendPlainText("**client socket disconnected");
    tcpSocket->deleteLater();
    //    deleteLater();//QObject::deleteLater();
}

void MainWindow::onSocketReadyRead()
{
    while(tcpSocket->canReadLine()){
        ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine());
    }
}

void MainWindow::on_actStart_triggered()
{
    QString IP=ui->comboIP->currentText();//IP地址
    quint16 port=ui->spinPort->value();//端口
    QHostAddress addr(IP);
    tcpServer->listen(addr,port);//
    ui->plainTextEdit->appendPlainText("**开始监听...");
    ui->plainTextEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());
    ui->plainTextEdit->appendPlainText("**服务器端口:"+QString::number(tcpServer->serverPort()));

    ui->actStart->setEnabled(false);
    ui->actStop->setEnabled(true);

    LabListen->setText("监听状态:正在监听");
}

void MainWindow::on_actStop_triggered()
{
    if (tcpServer->isListening()) //tcpServer正在监听
    {
        tcpServer->close();//停止监听
        ui->actStart->setEnabled(true);
        ui->actStop->setEnabled(false);
        LabListen->setText("监听状态:已停止监听");
    }
}

void MainWindow::on_actClear_triggered()
{
    ui->plainTextEdit->clear();
}

void MainWindow::on_btnSend_clicked()
{
    QString msg=ui->editMsg->text();
    ui->plainTextEdit->appendPlainText("[out] "+msg);
    ui->editMsg->clear();
    ui->editMsg->setFocus();

    QByteArray str=msg.toUtf8();
    str.append("\r\n");//添加一个换行符
    tcpSocket->write(str);
}

void MainWindow::on_actHostInfo_triggered()
{
    QString hostName=QHostInfo::localHostName();//本地主机名
    ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");
    QHostInfo hostInfo=QHostInfo::fromName(hostName);

    QList<QHostAddress> addList=hostInfo.addresses();//
    if (!addList.isEmpty())
    for (int i=0;i<addList.count();i++)
    {
        QHostAddress aHost=addList.at(i);
        if (QAbstractSocket::IPv4Protocol==aHost.protocol())
        {
            QString IP=aHost.toString();
            ui->plainTextEdit->appendPlainText("本机IP地址:"+aHost.toString());
            if (ui->comboIP->findText(IP)<0)
                ui->comboIP->addItem(IP);
        }
    }
}

  • ui界面
    在这里插入图片描述

三、代码分享

后续会写基于QT实现的UDP通信工具,下面给出代码。

  • 16
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

梦想广东收租

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值