Qt多线程TCP服务器

1、功能实现

在这里插入图片描述

2、程序简易流程

用一个Map<String,int> 来存放客户端的 socket的ip和客户端的索引(从0开始)。
围绕着这个创建流程。
1、关键点在于如何处理由服务器发出的 new Socket 连接
2、明白socket 通信的关键信号以及流程
在这里插入图片描述

3、简单剖析部分代码

重要代码1:处理新到来的 socket

void CServerPool::dealNewSocket(qintptr socketDes)
{//处理新到来的 soketDes
    m_numT++;
    if(m_numT<=m_maxT){//处理 没有被超出的
        int index=0;
        if(!m_mapVec.isEmpty()){
            index=m_mapVec.begin().key();
            m_mapVec.remove(index);
        }
        else{
            index=m_numT-1;
        }
		if (!m_threadVec.at(index).m_thread->isRunning()) {
			m_threadVec.at(index).m_thread->start();
			delayMs(600);//延迟600ms 等待线程启动
		}
        emit m_threadVec.at(index).m_myT->newSocket(index,socketDes);//发送到new socket
    }
    else{
        m_numT=m_maxT;//避免前后的index出错

        int index = 0;
        if (!m_mapQue.isEmpty()) {
            index = m_mapQue.begin().key();
            m_mapQue.remove(index);
        }
        else {
            index = m_numQue;
            ++m_numQue;
        }
        if (!m_threadQ->isRunning()){
            m_threadQ->start();
            delayMs(600);//延迟600ms
        }
        emit m_queueT->newSocket(index,socketDes);
    }
}

重要代码2: 线程组 的socket的创建

void MyThread::dealNewSocket(int index,qintptr socketDes)
{
    qDebug()<<"当前线程id"<<QThread::currentThreadId();
    if (!m_socket) {
        m_socket = new MySocket;

        if (!m_socket->t0) {
            m_socket->t0 = new QTimer;
            connect(m_socket->t0, &QTimer::timeout, [=]() {
                double nowTime = QDateTime::currentDateTime().toSecsSinceEpoch();
                if (nowTime - m_socket->m_frontTime > m_socket->m_outTime) {
                    QString str = QString("%1 %2已经超时").arg(
                        m_socket->peerAddress().toString().mid(7)).arg(index);
                    m_socket->t0->stop();
                    if (m_socket->isOpen())
                        m_socket->close();
                    delayMs(1000);
                    emit timeOut(m_socket->index, str);
                }
            });
        }

        //读取
        connect(m_socket, &MySocket::readyRead, [=]() {
            m_socket->t0->stop();
            QByteArray data = m_socket->readAll();
            QString str = m_socket->peerAddress().toString().mid(7);
            QString ip=str+QString(" %1").arg(m_socket->index);
            emit sendData(ip, data);
            m_socket->m_frontTime = QDateTime::currentDateTime().toSecsSinceEpoch();
            m_socket->t0->start(1000);
        });
        //断开连接
        connect(m_socket, &QTcpSocket::disconnected, [=]() {
            QString str = QString("%1 %2已经断开连接呢").arg(
                m_socket->peerAddress().toString().mid(7)).arg(index);
            QString ip = m_socket->peerAddress().toString();
            emit socketDisConnected(m_socket->index, ip, str);
            m_socket->t0->stop();
            if(m_socket->isOpen())
                m_socket->close();
        });
    }
    m_socket->index = index;
    if(m_socket->isOpen())
        m_socket->close();
    m_socket->setSocketDescriptor(socketDes);//设置socket的标志
   
    QString ip=m_socket->peerAddress().toString();
    emit sendAddress(index,ip);
    m_socket->m_frontTime = QDateTime::currentDateTime().toSecsSinceEpoch();
    m_socket->t0->start(1000);//第一次需要自启
}

重要代码3: 队列线程对socket的创建

void QueueThread::dealNewSocket(int index, qintptr socketDes)
{
      MySocket *m_socket = new MySocket;
      m_socket->t0 = new QTimer;
      m_socket->setSocketDescriptor(socketDes);
      m_socket->index = index;
      QString ip=m_socket->peerAddress().toString().mid(7)+QString(" %1").arg(index);

      m_mapDsocket.insert(ip,m_socket);//添加到指定列表中
      //读取
      connect(m_socket->t0, &QTimer::timeout, [=]() {
          double nowTime = QDateTime::currentDateTime().toSecsSinceEpoch();

          if (nowTime - m_socket->m_frontTime > m_socket->m_outTime) {
              int lsIndex = m_socket->index;
              QString str = QString("%1 %2已经超时").arg(
                  m_socket->peerAddress().toString().mid(7)).arg(lsIndex);
              m_socket->t0->stop();
              if (m_socket->isOpen())
                  m_socket->close();
             
              delayMs(1000);
              emit timeOut(str);
          }
      });
      connect(m_socket, &MySocket::readyRead, [=]() {
		  m_socket->t0->stop();
          QByteArray data = m_socket->readAll();
          QString ip = m_socket->peerAddress().toString().mid(7)+
              QString(" %1").arg(m_socket->index);
          emit sendData(ip, data);
          m_socket->m_frontTime = QDateTime::currentDateTime().toSecsSinceEpoch();
          m_socket->t0->start(1000);
      });
      //断开连接
      connect(m_socket, &QTcpSocket::disconnected, [=]() {
          int lsIndex = m_socket->index;
          QString ip = m_socket->peerAddress().toString().mid(7)+QString(" %1").arg(lsIndex);
          QString str = QString("%1已经断开连接呢").arg(ip);
        
          emit socketDisConnected(lsIndex, ip, str);

          m_socket->t0->stop();//关闭定时器
          if (m_socket->isOpen()) {
              m_socket->close();
              delete m_socket;
          }
          m_mapDsocket.remove(ip);
      });
      emit sendAddress(index,ip);//返回成功的地址
      m_socket->t0->start(1000);
      m_socket->m_frontTime = QDateTime::currentDateTime().toSecsSinceEpoch();
}

gitee:https://gitee.com/chenseri/mutiServer
资源地址:https://download.youkuaiyun.com/download/a1ngel/82470844

Qt多线程TCP客户端是一种可以在Qt应用程序中使用的多线程网络通信工具。 在使用Qt多线程TCP客户端之前,首先需要创建一个TCP Socket对象,并使用connectToHost方法连接到服务器。连接成功后,可以使用write方法发送数据到服务器。 为了实现多线程,可以使用Qt中的QThread类。首先,创建一个继承自QThread的自定义线程类,并重写run方法。在run方法中,可以编写与服务器进行通信的代码。 为了在多个线程之间共享数据,可以使用Qt中的信号和槽机制。可以在客户端线程类中定义信号,并在需要发送数据时发射信号。然后,可以将信号与服务器连接的槽函数进行连接,以便在接收到信号时执行相应的操作。 在客户端线程类中还可以使用信号和槽机制实现与主线程的通信。例如,可以在主线程中定义一个槽函数,用于接收从客户端线程发射的信号,并更新界面或执行其他相关操作。 为了确保多线程的安全性,需要采取适当的线程同步措施。可以使用Qt中的Mutex或其他同步原语来保护共享数据,以避免竞争条件和数据损坏。 使用Qt多线程TCP客户端时,需要仔细处理异常情况,例如连接中断或网络错误。可以在连接断开时发射信号,以便在主线程中进行错误处理或重新连接。 总而言之,Qt多线程TCP客户端是一种在Qt应用程序中实现多线程网络通信的方法。通过合理的设计和使用线程同步机制,可以实现高效的并发通信,并确保数据的安全性和可靠性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值