QT QTcpServer多线程服务器

2 篇文章 0 订阅

客户端程序

1. 在.pro工程文件中,加入qt 网络支持

QT       += core gui \
            network

2.创建 ClientSocket 类

客户端的主要功能包括:

连接服务器,断开服务器,接收并显示服务器数据,向服务器发送数据

//.h
class ClientSocket : public QTcpSocket
{
     Q_OBJECT

public:
    explicit ClientSocket(QObject *parent = Q_NULLPTR);
    ~ClientSocket();

    bool CilentConect(QHostAddress hadd,ushort port);//连接服务器
    void CilentBreakConect();//断开服务器
    void TransMess(QString str);//向服务器发送数据

signals:
    void dataReady(const QString &ip, const QByteArray &data);//从服务器接收到数据后向界面层发送信号

private slots:
    void recvData();//对QTcpSocket 接收到数据产生的信号设定的槽函数
};


//.cpp
ClientSocket::ClientSocket(QObject *parent) :QTcpSocket(parent)
{
    connect(this,SIGNAL(readyRead()),this,SLOT(recvData()));//底层信号readyRead -> 槽函数recvDate
}

ClientSocket::~ClientSocket()
{
   
}


bool ClientSocket::CilentConect(QHostAddress hadd,ushort port)
{
    this->connectToHost(hadd,port);
    if (this->waitForConnected(1000))  // 连接成功则true
    {
        return true;
    }
    return false;
}

void ClientSocket::CilentBreakConect()
{
    this->disconnectFromHost();//断开连接
}

void ClientSocket:: TransMess(QString str)//发送数据
{
   this->write(str.toLocal8Bit());
}

void ClientSocket:: recvData() //从服务器接收到数据后
{
    QString ip = peerAddress().toString().remove(0, 7);
    QByteArray data = readAll();
    emit dataReady(ip, data); //向界面层发送带数据的信号量
}

3.客户端以及ui设计

//.h
class Widget : public QWidget
{
    Q_OBJECT

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

private slots:
    void on_pushButton_Connect_clicked();//连接与断开服务器槽函数
    void on_pushButtonTrans_clicked();//发送数据槽函数
    void recvData(const QString &ip, const QByteArray &data);//接收数据处理槽函数
private:
    Ui::Widget *ui;
    ClientSocket *Cilent;//客户端Socket类
};


//.cpp
Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);
    Cilent = new ClientSocket(parent);
//客户端类接收到数据的信号连接到界面处理函数
    connect(Cilent, SIGNAL(dataReady(const QString&, const QByteArray&)),this, SLOT(recvData(const QString&, const QByteArray&)));
}

服务器端程序

服务器端程序的主要思路是,创建一个  QTcpServer 来侦听某一个端口,当有客户端接入时,启动一个线程,并创建一个Socket与对应的客户端通讯。所以这里涉及到四个部分:界面类,服务器类,通讯线程处理和服务器Socket。

服务器端及UI设计

 

//.h
class Widget : public QWidget
{
    Q_OBJECT

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

public:
    void showNewConnection(int sockDesc);//提示新连接  sockDesc:客户端ID
    void showDisconnection(int sockDesc);//提示连接断开

signals:
    void MessOk(const QString &mess);

private slots:
    void MessWindUpdate(const QString &mess);
    void on_pushButton_Trans_clicked();  //发送数据按键响应槽函数
    void on_pushButton_StartServer_clicked();//启动或关闭服务器槽函数

signals:
    void sendData(int id, const QByteArray &data); //发送数据产生信号

public slots:
    void recvData(const QString &ip, const QByteArray &data);//接收到数据后的处理槽函数

private:
    Ui::Widget *ui;
    Server *m_Server;
};

//.c

void Widget::on_pushButton_StartServer_clicked()
{
    QHostAddress address;

    if(ui->pushButton_StartServer->text() == "启动服务器")
    {
        QString localHostName = QHostInfo::localHostName();  //获取主机名
        ui->textBrowser_ServerMess->insertPlainText(localHostName+'\n');
        QHostInfo info = QHostInfo::fromName(localHostName); //获取主机IP

        foreach(address,info.addresses())//获取IPV4的第一个ip
        {
             if(address.protocol() == QAbstractSocket::IPv4Protocol) 
             {
                 ui->textBrowser_ServerMess->insertPlainText(address.toString()+'\n');
                 break;
             }
        }

        QString serIP = address.toString();//获取IP
        QString serPort = ui->lineEdit_Port->text();//获取端口

        m_Server->listen((QHostAddress)serIP,serPort.toUInt());//启动监听
        ui->pushButton_StartServer->setText("关闭服务器");
    }else if(ui->pushButton_StartServer->text() == "关闭服务器")
    {
        m_Server->close();//关闭服务器
        ui->pushButton_StartServer->setText("启动服务器");
    }

}

服务器类:

//.h
class Server : public QTcpServer
{
    Q_OBJECT
public:
    explicit Server(QObject *parent = Q_NULLPTR);
    ~Server();

private:
    void incomingConnection(int sockDesc);  //QTcpServer中被重写的函数,该函数在客户端接入时被调用

private slots:
    void clientDisconnected(int sockDesc); //当产生客户端断开连接时向上层发送信号

private:
    Widget *m_widget;  //上层界面的句柄 便于底层 服务器进程类的 信号量直接连接到界面处理函数

    QList<int> m_socketList; //服务器Socket ID链表
};

//.cpp
//这里的Server类继承于QTcpServer,
//重写其中的void incomingConnection(int sockDesc)方法,
//该方法在有客户端接入时自动调用。
//每当一个新的客户端连接时,通过标识码socketDescriptor,实现与对应的客户端通信
void Server::incomingConnection(int sockDesc)
{
    m_socketList.append(sockDesc);//客户端ID 加入链表

    ServThread *thread = new ServThread(sockDesc); //创建服务器处理进程

    m_widget->showNewConnection(sockDesc); //界面提示,新客户端接入 

//服务器进程发出消息,告诉服务器,XX客户端断开连接
    connect(thread, SIGNAL(disconnectTCP(int)), this, SLOT(clientDisconnected(int)));
//服务器进程发出消息给窗口,从哪个ip收到数据,槽函数由窗口构建
    connect(thread, SIGNAL(dataReady(const QString&, const QByteArray&)),
            m_widget, SLOT(recvData(const QString&, const QByteArray&)));
//窗口向服务器进程发出信号 以客户端ID 为标识,发出数据,槽函数由服务器进程构建
    connect(m_widget, SIGNAL(sendData(int, const QByteArray&)),
            thread, SLOT(sendDataSlot(int, const QByteArray&)));
//启动进程
    thread->start();
}

//这是一个槽函数 用于在界面上显示服务器断开了
void Server::clientDisconnected(int sockDesc)
{
    m_widget->showDisconnection(sockDesc);
}

服务器通讯线程类

//.h
class ServThread : public QThread
{
    Q_OBJECT
    public:
    explicit ServThread(int sockDesc, QObject *parent = Q_NULLPTR);
    ~ServThread();

private:
    void run(void);

public slots:
    void sendDataSlot(int sockDesc, const QByteArray &data);

signals:
    void dataReady(const QString &ip, const QByteArray &data);
    void sendData(int sockDesc, const QByteArray &data);
    void disconnectTCP(int sockDesc);

private slots:
    void recvDataSlot(const QString &ip, const QByteArray &data);
    void disconnectToHost(void);

private:
    ServSocket *m_socket;

    int m_sockDesc;
};

//.c
void ServThread:: sendDataSlot(int sockDesc, const QByteArray &data)
{
    emit sendData(sockDesc, data);
}


void ServThread:: recvDataSlot(const QString &ip, const QByteArray &data)
{
    emit dataReady(ip, data);
}

void ServThread:: disconnectToHost(void)
{
    emit disconnectTCP(m_sockDesc);
    m_socket->disconnectFromHost();//断开连接
    this->quit();
}

void ServThread::run(void)
{
    m_socket = new ServSocket(m_sockDesc);

    if (!m_socket->setSocketDescriptor(m_sockDesc)) {
        return ;
    }

    connect(m_socket, &ServSocket::disconnected, this, &ServThread::disconnectToHost);
    connect(m_socket, SIGNAL(dataReady(const QString&, const QByteArray&)),
            this, SLOT(recvDataSlot(const QString&, const QByteArray&)));
    connect(this, SIGNAL(sendData(int, const QByteArray&)),
            m_socket, SLOT(sendData(int, const QByteArray&)));

    this->exec();//在Qt中启动消息机制 龟腚
}

服务器Socket类

//.h
class ServSocket: public QTcpSocket
{
    Q_OBJECT
public:
    explicit ServSocket(int sockDesc, QObject *parent = Q_NULLPTR);
    ~ServSocket();

signals:
    void dataReady(const QString &ip, const QByteArray &data);

public slots:
    void recvData(void);
    void sendData(int id, const QByteArray &data);

private:
    int m_sockDesc;
};

//.c
ServSocket::ServSocket(int sockDesc,QObject *parent) :QTcpSocket(parent)
{
 m_sockDesc = sockDesc;
 connect(this,SIGNAL(readyRead()),this,SLOT(recvData()));//底层信号readyRead -> recvDate
}

ServSocket::~ServSocket()
{

}


void ServSocket:: recvData()
{
    QString ip = peerAddress().toString().remove(0, 7);
    QByteArray data = readAll();
    emit dataReady(ip, data);
}

void ServSocket:: sendData(int id, const QByteArray &data)
{
    if (id == m_sockDesc && !data.isEmpty()) {
        this->write(data);
    }
}

源码下载链接

https://download.csdn.net/download/zhaopeng6b/14193041

 

  • 7
    点赞
  • 83
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
QTcpServerQt中用于实现TCP服务器的类,它可以监听指定的端口并接受客户端的连接请求。在多线程中使用QTcpServer可以实现同时处理多个客户端的连接请求,提高服务器的并发性能。具体实现方法是继承QTcpServer类并重写incomingConnection函数,在该函数中为每个客户端连接分配一个新的线程,并将该连接交给该线程处理。在处理过程中,可以使用QTcpSocket类与客户端进行通信。同时,为了避免线程之间的资源竞争,需要使用QMutex等线程同步机制进行保护。 以下是一个简单的QTcpServer多线程实现的示例代码: ``` class MyTcpServer : public QTcpServer { Q_OBJECT public: explicit MyTcpServer(QObject *parent = nullptr); protected: void incomingConnection(qintptr socketDescriptor) override; signals: void sentData(const QByteArray &data, int handle); void sockDisConnect(int handle, QString ip, quint16 prot); private slots: void sockDisConnectSlot(int handle, QString ip, quint16 prot); private: QHash<int, MyTcpSocket*> tcpClient; QMutex mutex; }; void MyTcpServer::incomingConnection(qintptr socketDescriptor) { MyTcpSocket *tcpSocket = new MyTcpSocket(this); tcpSocket->setSocketDescriptor(socketDescriptor); QThread *thread = new QThread(this); tcpSocket->moveToThread(thread); connect(thread, &QThread::finished, tcpSocket, &QObject::deleteLater); connect(this, &MyTcpServer::sentData, tcpSocket, &MyTcpSocket::sentData); connect(tcpSocket, &MyTcpSocket::disconnected, thread, &QThread::quit); connect(tcpSocket, &MyTcpSocket::disconnected, this, &MyTcpServer::sockDisConnectSlot); mutex.lock(); tcpClient.insert(socketDescriptor, tcpSocket); mutex.unlock(); thread->start(); } void MyTcpServer::sockDisConnectSlot(int handle, QString ip, quint16 prot) { mutex.lock(); MyTcpSocket *tcp = tcpClient.value(handle); tcpClient.remove(handle); mutex.unlock(); tcp->deleteLater(); emit sockDisConnect(handle, ip, prot); } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值