同时处理多个Qtcp连接以显示在大理石小部件上

问题描述 投票:0回答:1

我有一个带有qt creator的应用程序,该应用程序可以获取地理坐标数据并将其显示在地图上。仅通过一个连接就可以很好地工作,但是涉及到不止一次时,这使它成为一个谜。我想从具有不同地址和端口的多个qtcp连接中循环获取数据,然后将数据放入单独的列表中,并在读取每个连接的地理数据列表后,在地图上的不同线程中添加单独的图层,每3秒更新一次,而所有这些从网络数据包中同时获取数据。假设我有许多不同的GPS接收器来收集它们的位置数据,我想将其集成到地图上。这是我的代码示例:

1。定义应连接qtcp客户端的服务器列表:

globals.cpp

#define PACKET 50
struct Connects{
    static QMap<QString,int> list()
        {
          QMap<QString,double> m;
          m["receiver1.com"] = 4456;
          m["receiver2.com"] = 4457;
          m["receiver3.com"] = 4458;
          return m;
        }
    static const QMap<QString,int> myMap;

};
QMap<QString, int> const Connects::myMap = list();

2。启动地图的主窗口:

main.cpp

void add_layer(MarbleWidget *mapWidget,Client *client){
        // Add New Layer based on positions in the list
        MPaintLayer* layer = new MPaintLayer(mapWidget);
        for(int j = 0; j < client->data.count(); ++j){
                layer->setPosition(client->data.at(j).Lat,client->data.at(j).Lon);
        }
        mapWidget->addLayer(layer);
}

MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
{
    // Load Marble
    MarbleWidget *mapWidget = new MarbleWidget;
    mapWidget->show();
    //iterate over connections address and port list
    QMapIterator<QString,int> i(Connects::myMap);
    while (i.hasNext()) {
        i.next();
        client = new Client;
        client->ConnectToServer(i.key(),i.value());
        //get data and append to a list every 3 sec
        timer = new QTimer;
        connect(timer,SIGNAL(timeout()),this,SLOT(online_slot()));
        timer->start(3000);
        mapWidget->update();
        //make thread pool and create new thread for adding each layer
        QThreadPool pool;
        QFuture<void> tr;
        tr = QtConcurrent::run(&pool,add_layer,mapWidget,client);
    }
}
void MainWindow::online_slot()
{
     //fetch data from the buffer and separate each entity based on size
     while (client->GetLanBufferSize() >= PACKET) {
          client->ReadData((char*)buffer,PACKET);
          double lat,lon;
          memcpy(&lat,&buffer[8],sizeof(double));
          memcpy(&lon,&buffer[16],sizeof(double));
          //put buffer data to target list which is defined in client
          Target trg;
          client->data.append(trg);
     }
    //remove has-readed data
    for (int var = 0; var < client->data.count(); ++var) {
        client->data.removeAt(var);
        var--;
    }
}

3.declare类,用于基于地图上收到的数据添加或更新新图层:

paintlayer.cpp

MPaintLayer::MPaintLayer(MarbleWidget* widget) 
{
    S_N = QPixmap(":/mode-s.png");
}
bool MPaintLayer::render( GeoPainter *painter,ViewportParams *viewport,
                          const QString& renderPos, GeoSceneLayer * layer )
{
    //throw a tiny png file on map based on retrieved locations
    for (int var = 0; var < pos.count(); ++var) {
        painter->drawPixmap(pos[var],S_N));
    }
    return true;
}
void MPaintLayer::setPosition(double lat,double lon)
{
  pos.append(GeoDataCoordinates(lat,lon,0,GeoDataCoordinates::Degree));

}

5。为接收到的数据的格式定义一个类:

client.h

class Target
{
public:
    Target()
    {
        Lat = Lon = 0;
    }
    double Lat,Lon;
    GeoDataCoordinates Position;
    void update(double lat,double lon)
    {
        Lat = lat;
        Lon = lon;
        Position = GeoDataCoordinates(Lon,Lat,0,GeoDataCoordinates::Degree);
    }
};

6.declare类,用于建立新的qtcp连接并接收数据:

client.cpp

Client::Client(QObject *parent) : QObject(parent)
{
    socket = new QTcpSocket(this);
    connect(socket, SIGNAL(connected()),this, SLOT(on_connected()));
}
void Client::on_connected()
{
    connect(socket, SIGNAL(disconnected()),this, SLOT(on_Disconnected()));
    socket->setReadBufferSize(12e6);
    emit Client_Connected();
}
bool Client::ReadData(char *buffer, int Leanth)
{
    socket->read(buffer , Leanth);
    return true;
}
int Client::GetLanBufferSize()
{
    return socket->bytesAvailable();
}
void Client::on_Disconnected()
{
    emit Client_DisConnected();
}
void Client::ConnectToServer(QString Address , int Port)
{
    socket->connectToHost(Address, Port);
    server = Address;
    server_Port = Port;
}

最佳实践解决方案是什么?因为它在地图上什么也没有显示。当我使用硬代码时,它显示的层数相当于每个连接,但是读取数据流是具有挑战性的。任何线索将不胜感激。

qt qthread qtcpsocket qtconcurrent marble
1个回答
0
投票

您未以正确的方式使用QTcpSocket。在您的Client类中,您可以处理所有阅读材料,甚至不需要那些while循环。在插槽中使用QIODevice::readyRead()信号和QIODevice::read(char *data, qint64 maxSize)方法,该插槽应读取并解析数据。

这里的问题是,不能保证将以发送方发生的对齐方式接收到这些数据。例如,如果您从发送方发送>>>SOME_LENGTHY_DATA<<<,则QTcpSocket可能会发出两次readyRead()信号,并且您可以在两次不同的读取插槽调用中读取>>>SOME_LENGTHY_DATA<<<

因此,您应该注意解析数据,因为数据将以逐字节输入。您可以自由地将传入数据缓冲在类中的某个位置,也可以只使用QTcpSocket内部缓冲区。您应该真正注意分离传入的消息块。

© www.soinside.com 2019 - 2024. All rights reserved.