【QT】使用TCP实现服务器端越客户端通信

1,窗口设计

为了便于代码部分阅读,现将窗口各部分objectName名称展示如下

1.1  服务器端窗口设计

[1],listWidget

[2], portEdit

[3],createButton

 

 1.2 客户端窗口设计

[1],  listWidget

[2], messageEdit

[3], sendButton

[4], serveripEdit

[5], serverPortEdit

[6], usernameEdit

[7], connectButton

 

2, 实现效果

 

 

3,实现原理

 3.1, 服务端主要使用QTcpSeverQTcpSocket类,QTcpSever用于创建TCP服务,QTcpSocket用于控制建立的socket连接。

3.1.1 创建TCPserver对象

3.1.2 使用listen()监听IP端口

3.1.3 当有新的连接时,会发出newConnection信号,触发槽函数接受并产生连接的套接字QTcpSocket

3.1.4 使用readyRead信号表示Socket缓存接收到新的数据

 3.2 客户端只使用 QTcpSocket

3.2.1 创建QTcpSocket对象

3.2.2 使用connectToHost()连接服务器IP和端口号

3.2.3 绑定connecteddisconnected信号

3.2.4 发送数据给服务端

 

4,具体代码部分

4.1 服务器端

4.1.1 头文件部分.h,主要一些声明,不做过多解释

#ifndef SERVERDIALOG_H
#define SERVERDIALOG_H

#include <QDialog>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QTimer>

namespace Ui {
class ServerDialog;
}

class ServerDialog : public QDialog
{
    Q_OBJECT

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

private slots:
    void on_createButton_clicked();
    void onNewConnection();
    void onReadyRead();
    void sendMessage(const QByteArray& buf);
    void onTimeout(void);

private:
    Ui::ServerDialog *ui;
    QTcpServer tcpserver;
    quint16 port;
    QList<QTcpSocket*> tcpClientList;
    QTimer timer;
};

#endif // SERVERDIALOG_H

 

4.1.2 具体.cpp部分实现#include "serverdialog.h"

#include "ui_serverdialog.h"

ServerDialog::ServerDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ServerDialog)
{
    ui->setupUi(this);
  //创建TcpServer连接 connect(
&tcpserver,&QTcpServer::newConnection,this,&ServerDialog::onNewConnection);
  //处理超时连接 connect(
&timer,&QTimer::timeout,this,&ServerDialog::onTimeout); } ServerDialog::~ServerDialog() { delete ui; }
//创建服务按钮槽函数实现
void ServerDialog::on_createButton_clicked() {
//获取端口
port
= ui->portEdit->text().toShort();
//创建监听
if(tcpserver.listen(QHostAddress::Any,port)==true) { qDebug() << "create server success!"; //创建按钮置灰,端口编辑置灰 ui->createButton->setEnabled(false); ui->portEdit->setEnabled(false);
//设置超时时间 timer.start(
3000); }else { qDebug() << "create server false!"; } }

//实现新连接槽函数
void ServerDialog::onNewConnection() {

//创建QTcpSocket连接套接字 QTcpSocket
* tcpClient = tcpserver.nextPendingConnection();
//将套接字指针添加进链表中,实现多客户端访问 tcpClientList.append(tcpClient);
//读取客户端数据 connect(tcpClient,
&QTcpSocket::readyRead,this,&ServerDialog::onReadyRead); }

//实现读取客户端数据
void ServerDialog::onReadyRead() {

//遍历所有客户端
for(int i=0;i<tcpClientList.size();i++) { if(tcpClientList.at(i)->bytesAvailable()) {
//读取并显示数据 QByteArray buf
= tcpClientList.at(i)->readAll(); ui->listWidget->addItem(buf); ui->listWidget->scrollToBottom(); sendMessage(buf); } } }

//将信息分发给所有客户端
void ServerDialog::sendMessage(const QByteArray& buf) { for(int i=0;i<tcpClientList.size();i++) { tcpClientList.at(i)->write(buf); } }
//超时报错
void ServerDialog::onTimeout(void) { for(int i=0;i<tcpClientList.size();i++) { if(tcpClientList.at(i)->state() == QAbstractSocket::UnconnectedState) { tcpClientList.removeAt(i); --i; } } }

 

4.2 客户端

4.2.1 头文件 .h

#ifndef CLIENTDIALOG_H
#define CLIENTDIALOG_H

#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QMessageBox>
#include <QDebug>

namespace Ui {
class ClientDialog;
}

class ClientDialog : public QDialog
{
    Q_OBJECT

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

private slots:
    void on_sendButton_clicked();

    void on_connectButton_clicked();

    void onConnected();

    void onDisconnected();

    void onReadyRead();

    void onError();

private:
    Ui::ClientDialog *ui;
    bool status;
    QTcpSocket tcpSocket;
    QHostAddress serverIP;
    quint16 serverPort;
    QString username;
};

#endif // CLIENTDIALOG_H

 

4.2.1 具体.cpp实现#include "clientdialog.h"#include "ui_clientdialog.h"

ClientDialog::ClientDialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::ClientDialog)
{
    ui->setupUi(this);
    status = false;
    connect(&tcpSocket,&QTcpSocket::connected,this,&ClientDialog::onConnected);
    connect(&tcpSocket,&QTcpSocket::disconnected,this,&ClientDialog::onDisconnected);
    connect(&tcpSocket,&QTcpSocket::readyRead,this,&ClientDialog::onReadyRead);
    connect(&tcpSocket, QOverload<QAbstractSocket::SocketError>::of(&QAbstractSocket::error),
            this,&ClientDialog::onError);
}

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

//发送信息按钮槽函数实现
void ClientDialog::on_sendButton_clicked() { QString msg = ui->messageEdit->text(); if(msg == "") { return; } msg = username + ":" + msg; tcpSocket.write(msg.toUtf8()); ui->messageEdit->clear(); }
//连接服务器端代码实现
void ClientDialog::on_connectButton_clicked() { if(status == false) {
serverIP.setAddress(ui
->serveripEdit->text()); serverPort = ui->serverPortEdit->text().toShort(); username = ui->usernameEdit->text();
//连接地址与端口号,连接服务器 tcpSocket.connectToHost(serverIP,serverPort); }
else { QString msg = username + "leave the talk room!"; tcpSocket.write(msg.toUtf8()); tcpSocket.disconnectFromHost(); } }

//实现连接槽函数
void ClientDialog::onConnected() { status = true; ui->sendButton->setEnabled(true); ui->serveripEdit->setEnabled(false); ui->serverPortEdit->setEnabled(false); ui->usernameEdit->setEnabled(false); ui->connectButton->setText("leave talk room"); QString msg = username + ":enter the talk room"; tcpSocket.write(msg.toUtf8()); } void ClientDialog::onDisconnected() { status = false; ui->sendButton->setEnabled(true); ui->serveripEdit->setEnabled(false); ui->serverPortEdit->setEnabled(false); ui->usernameEdit->setEnabled(false); ui->connectButton->setText("connect the server"); }
//读取数据内容
void ClientDialog::onReadyRead() { if(tcpSocket.bytesAvailable()) { QByteArray buf = tcpSocket.readAll(); ui->listWidget->addItem(buf); ui->listWidget->scrollToBottom(); } } //显示报错信息 void ClientDialog::onError() { QMessageBox::critical(this,"ERROR",tcpSocket.errorString()); }

 

posted @ 2022-08-06 15:40  老年新手工程师  阅读(279)  评论(0编辑  收藏  举报