QTcp

本次分享下关于QTcp*的使用。我们的服务端为客户端发送图片。

服务端,继承QTcpServer,重写incomingConnection方法。

  • 一个线程,一个map来管理客户端的socket描述符。
  • 重写incomingConnection,从源头获取客户端的套接字描述符

实现如下:

class CusTcpServer:public QTcpServer
{
    Q_OBJECT
public:
    CusTcpServer(QObject *parent = nullptr);
    ~CusTcpServer();
    //新连接直接获取套接字描述符
    void incomingConnection(qintptr socketDescriptor) override;

    bool insertSocketMap(qintptr fd,CusSocket *socket);

    void sendImage(CusSocket *socket);
signals:
    void sig_debugOutPut(QString info);

public slots:
    // 监听
    void slot_startListen();

private:
    QMap<qintptr,CusSocket*> map_clientSocket;
    QThread *m_thread;
    QImage m_image;
};
CusTcpServer::CusTcpServer(QObject *parent)
    :QTcpServer (parent)
{
    m_image.load(":/image/111.jpg");
    m_thread = new QThread;
    this->moveToThread(m_thread);
    m_thread->start();
}

CusTcpServer::~CusTcpServer()
{
    qDeleteAll(map_clientSocket.begin(),map_clientSocket.end());
    map_clientSocket.clear();

    m_thread->quit();
    m_thread->deleteLater();
    m_thread = nullptr;
}

void CusTcpServer::incomingConnection(qintptr socketDescriptor)
{
    // 处于线程
    CusSocket *t_socket = new CusSocket(socketDescriptor);// 不可指定父亲
    t_socket->moveToThread(m_thread);
    connect(t_socket, &QTcpSocket::readyRead, t_socket, &CusSocket::slot_getMessage);

    // add
    insertSocketMap(socketDescriptor, t_socket);

    // sendimage ,more to do
    sendImage(t_socket);
}

bool CusTcpServer::insertSocketMap(qintptr fd, CusSocket *socket)
{
    bool ret = false;
    if(!map_clientSocket.contains(fd))
    {
        map_clientSocket.insert(fd,socket);
        ret = true;
    }
    return ret;
}

void CusTcpServer::sendImage(CusSocket *socket)
{
    // 字节
    QByteArray bytes;
    QBuffer buffer;
    m_image.save(&buffer,"JPG");
    bytes.append(buffer.data());
    socket->write(bytes);
}

void CusTcpServer::slot_startListen()
{
    // 使用信号和槽连接,线程中
    if(!this->isListening())
    {
        QHostAddress address = QHostAddress::LocalHost;
        quint16 port = 6789;
        bool ret = listen(address,port);
        emit sig_debugOutPut(QString("server listen ip:%1 , port:%2, ret = %3").arg(address.toString()).arg(port).arg(ret));
    }
    emit sig_debugOutPut("server is already listening");
}

由于我们将server移入到其他线程,最好将其操作都置于槽函数中,eg:我们对listen进行包裹,有新的连接时,触发 incomingConnection方法,该方法位于线程中,获取源描述符,并移到线程中。

客户端,继承QTcpSocket,连接时,connectToHost即可。

class CusSocket:public QTcpSocket
{
    Q_OBJECT
public:
    CusSocket(qintptr socketDescriptor,QObject *parent = nullptr);
public slots:
    void slot_getMessage();

private:
    qintptr m_fd;
};
CusSocket::CusSocket(qintptr socketDescriptor, QObject *parent)
    :QTcpSocket(parent)
{
    m_fd = socketDescriptor;
    setSocketDescriptor(m_fd);
}

void CusSocket::slot_getMessage()
{
    if(bytesAvailable() <= 0)
    {
        return;
    }
    QByteArray dataBytes = readAll();
    QImage image = QImage::fromData(dataBytes,"JPG");
    image.save("D:/tcpget.jpg","JPG",100);
}

本次发送的数据比较小,重点在于理解重写incomingConnection方法获取源描述符和线程管理。

猜你喜欢

转载自blog.csdn.net/qq_39175540/article/details/85694317