TCP通信如何实现服务端连多客户端

时间:2022-10-12 22:15:49
初学QT,不太熟,改了好多,都只能连一个客户端,第二个连不上,有做过的帮忙看看吗,谢谢!
服务端cpp
#include "TcpServer.h"

TcpServer::TcpServer(QObject *parent) :
    QObject(parent),
    _pTcpSocket(0),
    _connected(false)
{
    _pTcpServer = new QTcpServer(this);

    _pTcpServer->listen(QHostAddress::AnyIPv4, 5050);

    connect(_pTcpServer, SIGNAL(newConnection()), this, SLOT(newConnection()));

}

void TcpServer::newConnection()
{
    if(_pTcpSocket) {
        _pTcpSocket->disconnect();
        _pTcpSocket->close();
        _pTcpSocket->deleteLater();
        _pTcpSocket = 0;
    }
    _pTcpSocket = _pTcpServer->nextPendingConnection();
    connect(_pTcpSocket, SIGNAL(readyRead()), this, SLOT(readReady()));
    connect(_pTcpSocket, SIGNAL(disconnected()), this, SLOT(disConnection()));
    _connected = true;
    emit stringMessage(QString("%2").arg(_pTcpSocket->peerAddress().toString()));
}



void TcpServer::readReady()
{
    QByteArray byteArray = _pTcpSocket->readAll();
    // S23.5,51E
    QString tmp(byteArray);
    if(tmp.startsWith("F") && tmp.endsWith("I")) {
        QString t = tmp.mid(1, tmp.indexOf(",")-1);
        QString h = tmp.mid(tmp.indexOf(",")+1, tmp.size()-tmp.indexOf(",")-2);
        emit temperature(t);
        emit humidity(h);
    }

}

void TcpServer::disConnection()
{
    _connected = false;
    emit stringMessage(QString("%2").arg(_pTcpSocket->peerAddress().toString()));
   // _pTcpSocket->close();
    _pTcpSocket->deleteLater();
    _pTcpSocket = 0;
}

void TcpServer::sendData(QString cmd)
{
    if(_connected) {
        _pTcpSocket->write(cmd.toUtf8());
        _pTcpSocket->flush();
    }
}

5 个解决方案

#1


服务器,incomingConnection()重写

#2


有几个问题:
1、你的TcpServer类为什么不直接继承自QTcpServer?
2、服务器要连接多个客户端时,一定要相应的在服务器端基于QTcpSocket建立多个实例,你的没有这部分内容!
3、一般服务器使用incomingConnection()函数参数中的套接字,来判断该客户端的套接字是新链接还是已经建立好的连接?
4、服务器端要建立基于QTcpSocket的列表,来管理多个客户端。

#3


你这么写同一时间只能有一个tcpsock存在。void TcpServer::newConnection()
{
    if(_pTcpSocket) {
        _pTcpSocket->disconnect();
        _pTcpSocket->close();
        _pTcpSocket->deleteLater();
        _pTcpSocket = 0;
    }

    _pTcpSocket = _pTcpServer->nextPendingConnection();
    connect(_pTcpSocket, SIGNAL(readyRead()), this, SLOT(readReady()));
    connect(_pTcpSocket, SIGNAL(disconnected()), this, SLOT(disConnection()));
    _connected = true;
    emit stringMessage(QString("%2").arg(_pTcpSocket->peerAddress().toString()));
}
我当初的做法是使用QList<QTcpSocket *>来维护多个连接,但是就是需要自己去分辨,是哪个连接可用,如果向方便一点,我觉得应该每一个新的连接,对应一个新的进程。我年后将要做这方面的工作。

#4


三步走:
1. 写一个新类继承QTcpServer
2. 重写incomingConnection
void QTcpServer::incomingConnection(qintptr socketDescriptor)

socketDescriptor是当前连接分配的描述符,根据这个描述符创建一个QTcpSocket实例(当然最好也是自己创建继承于这个东西的类),然后QTcpSocket::socketDescriptor(socketDescriptor),这个时候就可以通过socket来通讯了
3. 在继承QTcpServer类上创建一个List,或者是Map,来管理socket
(PS:如果是Map,Key千万不要用descriptor,要自己定义一个,可以模仿Unix的那个FIFO管道分配的那个方法,一开始随便指定一个数,然后来一个socket分配一个递增的key)

最后根据你服务器类型的需要来做一点完善的东西了,如果你要做比较好的多线程服务器,一个socket一个线程,把socket的disconnect信号绑定到QThread的finnished和deleteLater上,最后一个moveToThread把socket放到线程上去。

#5


为啥一定要继承嘞
    QTcpServer *m_pServer = new QTcpServer(this);
    connect(m_pServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));

void MainWindow::onNewConnection()
{
    //每个socket代表一个和客户端通信的实例
    QTcpSocket *socket = m_pServer->nextPendingConnection();
    connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));

    qDebug() << QString("新连接:peerAddress %1, localAddress %2").arg(socket->peerAddress().toString()).arg(socket->localAddress().toString());
}

#1


服务器,incomingConnection()重写

#2


有几个问题:
1、你的TcpServer类为什么不直接继承自QTcpServer?
2、服务器要连接多个客户端时,一定要相应的在服务器端基于QTcpSocket建立多个实例,你的没有这部分内容!
3、一般服务器使用incomingConnection()函数参数中的套接字,来判断该客户端的套接字是新链接还是已经建立好的连接?
4、服务器端要建立基于QTcpSocket的列表,来管理多个客户端。

#3


你这么写同一时间只能有一个tcpsock存在。void TcpServer::newConnection()
{
    if(_pTcpSocket) {
        _pTcpSocket->disconnect();
        _pTcpSocket->close();
        _pTcpSocket->deleteLater();
        _pTcpSocket = 0;
    }

    _pTcpSocket = _pTcpServer->nextPendingConnection();
    connect(_pTcpSocket, SIGNAL(readyRead()), this, SLOT(readReady()));
    connect(_pTcpSocket, SIGNAL(disconnected()), this, SLOT(disConnection()));
    _connected = true;
    emit stringMessage(QString("%2").arg(_pTcpSocket->peerAddress().toString()));
}
我当初的做法是使用QList<QTcpSocket *>来维护多个连接,但是就是需要自己去分辨,是哪个连接可用,如果向方便一点,我觉得应该每一个新的连接,对应一个新的进程。我年后将要做这方面的工作。

#4


三步走:
1. 写一个新类继承QTcpServer
2. 重写incomingConnection
void QTcpServer::incomingConnection(qintptr socketDescriptor)

socketDescriptor是当前连接分配的描述符,根据这个描述符创建一个QTcpSocket实例(当然最好也是自己创建继承于这个东西的类),然后QTcpSocket::socketDescriptor(socketDescriptor),这个时候就可以通过socket来通讯了
3. 在继承QTcpServer类上创建一个List,或者是Map,来管理socket
(PS:如果是Map,Key千万不要用descriptor,要自己定义一个,可以模仿Unix的那个FIFO管道分配的那个方法,一开始随便指定一个数,然后来一个socket分配一个递增的key)

最后根据你服务器类型的需要来做一点完善的东西了,如果你要做比较好的多线程服务器,一个socket一个线程,把socket的disconnect信号绑定到QThread的finnished和deleteLater上,最后一个moveToThread把socket放到线程上去。

#5


为啥一定要继承嘞
    QTcpServer *m_pServer = new QTcpServer(this);
    connect(m_pServer, SIGNAL(newConnection()), this, SLOT(onNewConnection()));

void MainWindow::onNewConnection()
{
    //每个socket代表一个和客户端通信的实例
    QTcpSocket *socket = m_pServer->nextPendingConnection();
    connect(socket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));

    qDebug() << QString("新连接:peerAddress %1, localAddress %2").arg(socket->peerAddress().toString()).arg(socket->localAddress().toString());
}