QT + Tcp客户端,服务器(支持多客户端)

环境

Qt 5.4.2

功能

QT Tcp 服务器,多客户端通信

服务器源码

在这里插入图片描述

  1. TcpServerApp.pro
    QT += network

  2. mainwindow

mainwindow.h

#include "tcpserver.h"

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;
private:
     QTreeWidgetItem *pServerItem;
     QTreeWidgetItem *pClientItem;
     QStandardItemModel* pClientModel;
     TcpServer  tcpServer;
private:
    void InitTreeView();
    void InitServerCfg();
    void InitClientCfg();
private slots:
    void slot_incomingConnect(QString socketID);
    void slot_readMessage(QString socketId,QString message);
    void slot_disconnected(QString socketId);
    void slot_itemDoubleClicked(QTreeWidgetItem *item, int column);
    void slot_curStateChanged(QString identify,int state);
    void on_pushButton_Start_clicked();
    void on_pushButton_Close_clicked();
    void on_pushButton_Send_clicked();
    void on_pushButton_SendAll_clicked();
    void on_pushButton_CloseAll_clicked();
};

class MyCheckBox : public QCheckBox
{
    Q_OBJECT
public:
    explicit MyCheckBox(){}
    ~MyCheckBox(){}
public:
    void SetIdentify(QString identify) { sIdentify = identify;
     connect(this,SIGNAL(stateChanged(int)),this,SLOT(slot_stateChanged(int)));}
signals:
    void curStateChanged(QString identify,int state);
private slots:
    void slot_stateChanged(int state){emit curStateChanged(sIdentify,state);}
private:
    QString  sIdentify;
};
#endif // MAINWINDOW_H

mainwindow.cpp

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

void MainWindow::InitTreeView()
{
    ui->treeWidget->setColumnCount(1);
    ui->treeWidget->setHeaderLabel(tr("TCP 服务器"));
    pServerItem = new QTreeWidgetItem(ui->treeWidget,QStringList(QString("服务器")));// 添加QTreeWidget主节点;
    pClientItem = new QTreeWidgetItem(ui->treeWidget,QStringList(QString("客户端")));
    QTreeWidgetItem *pServerItem_1 = new QTreeWidgetItem(pServerItem,QStringList(QString("配置管理")));
    QTreeWidgetItem *pClientItem_1 = new QTreeWidgetItem(pClientItem,QStringList(QString("配置管理")));
    connect(ui->treeWidget,SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int)),this,SLOT(slot_itemDoubleClicked(QTreeWidgetItem*,int)));
    ui->treeWidget->setCurrentItem(pServerItem_1);
    ui->treeWidget->expandAll();
    ui->stackedWidget->setCurrentIndex(0);
}

void MainWindow::InitServerCfg()
{
    connect(&tcpServer,SIGNAL(incomingConnect(QString)),SLOT(slot_incomingConnect(QString)));
    connect(&tcpServer,SIGNAL(readMessage(QString,QString)),SLOT(slot_readMessage(QString,QString)));
    connect(&tcpServer,SIGNAL(disconnected(QString)),SLOT(slot_disconnected(QString)));
    ui->pushButton_Start->setEnabled(true);
    ui->pushButton_Close->setEnabled(false);
}

void MainWindow::InitClientCfg()
{
    pClientModel = new QStandardItemModel();
    ui->tableView_RecvAll->verticalHeader()->setVisible(false);
    ui->tableView_RecvAll->horizontalHeader()->setVisible(false);
    ui->tableView_RecvAll->setModel(pClientModel);
    pClientModel->setColumnCount(2);                                
    ui->tableView_RecvAll->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
    ui->tableView_RecvAll->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
    ui->tableView_RecvAll->setColumnWidth(0, 80);
    ui->tableView_RecvAll->setEditTriggers(QAbstractItemView::NoEditTriggers);
    MyCheckBox *pAllCheck = new MyCheckBox();
    pAllCheck->setText("全选");
    pAllCheck->SetIdentify("All");
    connect(pAllCheck,SIGNAL(curStateChanged(QString,int)),this,SLOT(slot_curStateChanged(QString,int)));
    pClientModel->setRowCount(1);
    ui->tableView_RecvAll->setRowHeight(0,40);
    ui->tableView_RecvAll->setIndexWidget(pClientModel->index(0,0),pAllCheck);
    pClientModel->setItem(0, 1, new QStandardItem("客户端" ) );
    ui->pushButton_SendAll->setEnabled(false);
    ui->pushButton_CloseAll->setEnabled(false);
}
void MainWindow::slot_incomingConnect(QString socketID)
{
    QTreeWidgetItem *pClientItem_N = new QTreeWidgetItem(pClientItem,QStringList(socketID));
    pClientModel->setRowCount(pClientModel->rowCount()+1);
    MyCheckBox *pOneCheck = new MyCheckBox();
    pOneCheck->SetIdentify(socketID);
    connect(pOneCheck,SIGNAL(curStateChanged(QString,int)),this,SLOT(slot_curStateChanged(QString,int)));
    ui->tableView_RecvAll->setIndexWidget(pClientModel->index(pClientModel->rowCount()-1,0),pOneCheck);
    pClientModel->setItem(pClientModel->rowCount()-1, 1, new QStandardItem(socketID) );
    ui->tableView_RecvAll->setRowHeight(pClientModel->rowCount()-1,40);
}
void MainWindow::slot_readMessage(QString socketId, QString message)
{
    QString sSocketID =  "客户端[" + socketId + "]";
    if(ui->label_Info->text() == sSocketID)
    {
        ui->textEdit_Recv->setText(message);
    }
}
void MainWindow::slot_disconnected(QString socketId)
{
    for(int i=0; i<pClientItem->childCount(); i++)
    {
        if(pClientItem->child(i)->text(0) == socketId)
        {
            pClientItem->removeChild(pClientItem->child(i));
            break;
        }
    }
    
    for(int i=1; i<pClientModel->rowCount(); i++)
    {
        if(socketId == pClientModel->item(i,1)->text())
        {
            pClientModel->removeRow(i);
        }
    }
    ui->treeWidget->setCurrentItem(pClientItem->child(0));
    ui->stackedWidget->setCurrentIndex(1);
}

void MainWindow::slot_itemDoubleClicked(QTreeWidgetItem *item, int column)
{
    if(NULL == item->parent()) { return; }
    if(item->parent() == pServerItem)
    {
        ui->stackedWidget->setCurrentIndex(0);
        return;
    }
    if("配置管理" == item->text(0))
    {
       ui->stackedWidget->setCurrentIndex(1);
       return;
    }
    QString sTitleMsg  = "客户端[" + item->text(0) + "]";
    ui->label_Info->setText(sTitleMsg);
    ui->stackedWidget->setCurrentIndex(2);
    ui->textEdit_Send->clear();
    ui->textEdit_Recv->setText(tcpServer.GetRecvMesg(item->text(0)));
}

void MainWindow::slot_curStateChanged(QString identify, int state)
{
   if("All" != identify) { return; }
   MyCheckBox *pCheckBox;
   
   for(int i=1; i<pClientModel->rowCount(); i++)
   {
       pCheckBox = (MyCheckBox*)ui->tableView_RecvAll->indexWidget(pClientModel->index(i,0));
       switch(state)
       {
        case 0: pCheckBox->setChecked(false); break;
        case 2: pCheckBox->setChecked(true);  break;
        default:break;
       }
   }
}

void MainWindow::on_pushButton_Start_clicked()
{
    ui->label_ServerSts->setText("");
    if(!tcpServer.listen(QHostAddress::Any,ui->spinBox_Port->value()))
    {
        ui->label_ServerSts->setText("Failed to bind port !");
        return;
    }

    ui->pushButton_Start->setEnabled(false);
    ui->pushButton_Close->setEnabled(true);
    ui->pushButton_SendAll->setEnabled(true);
    ui->pushButton_CloseAll->setEnabled(true);
}

void MainWindow::on_pushButton_Close_clicked()
{
    tcpServer.close();
    tcpServer.ClearClientAll();
    ui->pushButton_Start->setEnabled(true);
    ui->pushButton_Close->setEnabled(false);
    ui->pushButton_SendAll->setEnabled(false);
    ui->pushButton_CloseAll->setEnabled(false);
}
void MainWindow::on_pushButton_Send_clicked()
{
    QString sSocketID =  ui->label_Info->text();
    sSocketID = sSocketID.mid(sSocketID.indexOf("[")+1,sSocketID.lastIndexOf("]") - sSocketID.indexOf("[")-1);
    tcpServer.SendMessage(sSocketID,ui->textEdit_Send->toPlainText());
    ui->textEdit_Send->clear();
    ui->textEdit_Recv->setText(tcpServer.GetRecvMesg(sSocketID));
}

void MainWindow::on_pushButton_SendAll_clicked()
{
    if("" == ui->textEdit_RecvAll->toPlainText()) { return; }
    MyCheckBox *pCheckBox;
    for(int i=1; i<pClientModel->rowCount(); i++)
    {
        pCheckBox = (MyCheckBox*)ui->tableView_RecvAll->indexWidget(pClientModel->index(i,0));
        switch(pCheckBox->checkState())
        {
          case Qt::Checked :
          {
            tcpServer.SendMessage(pClientModel->item(i,1)->text(),ui->textEdit_RecvAll->toPlainText());
          }break;
          default:break;
        }
    }
}

void MainWindow::on_pushButton_CloseAll_clicked()
{
    MyCheckBox *pCheckBox;
    for(int i=1; i<pClientModel->rowCount(); i++)
    {
        pCheckBox = (MyCheckBox*)ui->tableView_RecvAll->indexWidget(pClientModel->index(i,0));
        switch(pCheckBox->checkState())
        {
          case Qt::Checked :
          {
            tcpServer.CloseSocket(pClientModel->item(i,1)->text());
          }break;
          default:break;
        }
    }
}

  1. tcpserver
    tcpserver.h
#include "tcpsocket.h"

class TcpServer : public QTcpServer
{
    Q_OBJECT
public:
    TcpServer();
    ~TcpServer();
    void ClearClientAll();
    void SendMessage(QString socketId,QString message);
    void CloseSocket(QString socketId);
    QString GetRecvMesg(QString socketId);
protected:
    void incomingConnection(int socketId);
private:
    QMap<QString,TcpSocket *> clientArray;
private slots:
    void slot_readMsg(QString socketId,QString message);
    void slot_disconnect(QString socketId);
signals:
    void incomingConnect(QString socketId);
    void readMessage(QString socketId,QString message);
    void disconnected(QString socketId);
};
#endif // TCPSERVER_H

tcpserver.cpp

#include "tcpserver.h"

void TcpServer::ClearClientAll()
{
    for (QString key : clientArray.keys())
    {
        clientArray[key]->close();
    }
    clientArray.clear();
}

void TcpServer::SendMessage(QString socketId, QString message)
{
    if(clientArray.contains(socketId))
    {
        clientArray[socketId]->SendMessage(message);
    }
}
void TcpServer::CloseSocket(QString socketId)
{
    if(clientArray.contains(socketId))
    {
        clientArray[socketId]->close();
    }
}

QString TcpServer::GetRecvMesg(QString socketId)
{
    if(clientArray.contains(socketId))
    {
        return clientArray[socketId]->GetRecvMesg();
    }
}

void TcpServer::incomingConnection(int socketId)
{
   TcpSocket *pTcpSocket = new TcpSocket();
   pTcpSocket->setSocketDescriptor(socketId);
   QString sClientInfo =  "ID:"+QString::number(socketId) + ",IP:" + pTcpSocket->peerAddress().toString() + ":"+ QString::number(pTcpSocket->peerPort());
   pTcpSocket->SetSocketID(sClientInfo);
   clientArray.insert(sClientInfo,pTcpSocket);
   connect(pTcpSocket,SIGNAL(readMsg(QString,QString)),SLOT(slot_readMsg(QString,QString)));
   connect(pTcpSocket,SIGNAL(disconnect(QString)),SLOT(slot_disconnect(QString)));
   emit incomingConnect(sClientInfo);
}

void TcpServer::slot_readMsg(QString socketId, QString message)
{
    emit readMessage(socketId,message);
}

void TcpServer::slot_disconnect(QString socketId)
{
   clientArray[socketId]->close();
   clientArray.remove(socketId);
   emit disconnected(socketId);
}

  1. tcpsocket
    tcpsocket.h
class TcpSocket : public QTcpSocket
{
    Q_OBJECT
public:
    TcpSocket();
    ~TcpSocket();
    void SetSocketID(QString socketID);
    void SendMessage(QString message);
    QString GetRecvMesg();
private:
    QString sSocketID;
    QStringList sRecvMesg;
private slots:
    void slot_readyRead();
    void slot_disconnected();
signals:
    void readMsg(QString socketId,QString message);
    void disconnect(QString socketId);
};

#endif // TCPSOCKET_H

tcpsocket.cpp

TcpSocket::TcpSocket()
{
    sSocketID = "";
    sRecvMesg.clear();
    connect(this,SIGNAL(readyRead()),this,SLOT(slot_readyRead()));
    connect(this,SIGNAL(disconnected()),this,SLOT(slot_disconnected()));
}

void TcpSocket::SetSocketID(QString socketID)
{
    sSocketID = socketID;
}

void TcpSocket::SendMessage(QString message)
{
    this->write(message.toLatin1());

    if(sRecvMesg.count() > 1024) { sRecvMesg.removeAt(0);}

    QString sReadMsg = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + ": S -> " + message;
    sRecvMesg.append(sReadMsg);
}

QString TcpSocket::GetRecvMesg()
{
    return sRecvMesg.join("\n");
}

void TcpSocket::slot_readyRead()
{
    if(sRecvMesg.count() > 1024) { sRecvMesg.removeAt(0);}
    QString sReadMsg = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + ": R -> " + QString(this->readAll());
    sRecvMesg.append(sReadMsg);
    emit readMsg(sSocketID,sRecvMesg.join("\n"));
}
void TcpSocket::slot_disconnected()
{
    emit disconnect(sSocketID);
}

客户端源码

在这里插入图片描述

  1. TcpClientApp.pro
    QT += network

  2. mainwindow
    mainwindow.h

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();
private:
    Ui::MainWindow *ui;

private slots:
    void slot_connected();
    void slot_readyRead();
    void slot_disconnected();
    void on_pushButton_Connect_clicked();
    void on_pushButton_Send_clicked();
    void on_pushButton_Close_clicked();
private:
    QTcpSocket tcpSocket;
};
#endif // MAINWINDOW_H

mainwindow.cpp

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

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

    connect(&tcpSocket,SIGNAL(connected()),this,SLOT(slot_connected()));
    connect(&tcpSocket,SIGNAL(readyRead()),this,SLOT(slot_readyRead()));
    connect(&tcpSocket,SIGNAL(disconnected()),this,SLOT(slot_disconnected()));
    ui->label_sts->setText("disconnected");
    ui->pushButton_Connect->setEnabled(true);
    ui->pushButton_Send->setEnabled(false);
    ui->pushButton_Close->setEnabled(false);
}

void MainWindow::slot_connected()
{
    ui->label_sts->setText("connected");
    ui->pushButton_Connect->setEnabled(false);
    ui->pushButton_Send->setEnabled(true);
    ui->pushButton_Close->setEnabled(true);
}

void MainWindow::slot_readyRead()
{
    QString sMessage = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + ": R -> " + QString(tcpSocket.readAll());
    if(ui->textEdit_Recv->document()->lineCount() > 1024)
    {
        ui->textEdit_Recv->clear();
    }
    ui->textEdit_Recv->append(sMessage);
}

void MainWindow::slot_disconnected()
{
    ui->label_sts->setText("disconnected");
    ui->pushButton_Connect->setEnabled(true);
    ui->pushButton_Send->setEnabled(false);
    ui->pushButton_Close->setEnabled(false);
}
void MainWindow::on_pushButton_Connect_clicked()
{
    tcpSocket.connectToHost(QHostAddress(ui->lineEdit_IP->text()),ui->spinBox_Port->value());
}
void MainWindow::on_pushButton_Send_clicked()
{
    tcpSocket.write(ui->textEdit_Send->toPlainText().toLatin1());
    if(ui->textEdit_Recv->document()->lineCount() > 1024)
    {
        ui->textEdit_Recv->clear();
    }
    QString sMessage = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss:zzz") + ": S -> " + ui->textEdit_Send->toPlainText();
    ui->textEdit_Recv->append(sMessage);
    ui->textEdit_Send->clear();
}

void MainWindow::on_pushButton_Close_clicked()
{
    tcpSocket.close();
}

运行结果

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值