Russian Qt Forum
Ноябрь 23, 2024, 05:15 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: 2 пакета сливаются в один  (Прочитано 5606 раз)
Firefox
Гость
« : Декабрь 19, 2013, 14:15 »

Здравствуйте. у меня есть 2 программы клиент и сервер TCP. по сети общаются. пакет от сервера к клиету передается такой: длинна пакета, разделитель(|), заголовок пакета (KS), команда из 4-х цифр.так вот если пакеты передаются раз в пол секунды то иногда на стороне клиента приходит строка состоящая из 2-х последовательно записанных пакетов. если увеличить время например раз в 7 секунд то все в порядке. выводила пакеты на сервере перед самой функцией write и сразу после read на клиенте.
запись на сервере
Код:
void ClientSocket::slotSendData_pod(QByteArray arr)
{
    int sz=0;
    if(socket_out->state()!=QAbstractSocket::ConnectedState)
        return;

      sz=socket_out->write(arr);

    if(sz!=arr.size())
    {
        qDebug()<<"SV_P: not all information writes to protocol";
    }
}
чтение на клиенте
Код:
{
    QTcpSocket  *socket_in=(QTcpSocket *)sender();
    QByteArray arrData;
    arrData.resize(0);
    QDataStream in(socket_in);
    in.setVersion(QDataStream::Qt_4_2);
    quint64 NextBlockSize=0;
    for(;;)
    {
        if(!NextBlockSize)
        {
            if((unsigned)socket_in->bytesAvailable()<sizeof(quint16))
                break;
            NextBlockSize=socket_in->bytesAvailable();
        }
        if((unsigned)socket_in->bytesAvailable()<=NextBlockSize)
            break;
    }
        arrData= socket_in->read(NextBlockSize);

        if(arrData.size()>1)
        {
            QString pak=(QString)(arrData);
            QStringList Lst=pak.split(packetSeparator);
            qDebug()<<"IN"<<Lst;
....
}

Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #1 : Декабрь 19, 2013, 14:19 »

Это нормально, так и должно быть.
Можно воспользоваться флушем, но лучше сразу правильно разбирать несколько пакетов на принимающей стороне.
Записан
Firefox
Гость
« Ответ #2 : Декабрь 19, 2013, 15:22 »

flush не помог. честно говоря мне по сути алгоритма это не сильно хорошо Обеспокоенный. я надеялась принять пакет и отправить далее без всяких наворотов. потому как в есть необходимость соблюдать временные рамки для каждого пакета.
Записан
Old
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 4350



Просмотр профиля
« Ответ #3 : Декабрь 19, 2013, 15:27 »

flush не помог. честно говоря мне по сути алгоритма это не сильно хорошо Обеспокоенный. я надеялась принять пакет и отправить далее без всяких наворотов. потому как в есть необходимость соблюдать временные рамки для каждого пакета.
Пакеты объединяет сетевой стек. Это специальная мера, что бы уменьшить бесполезный трафик. Не стоит пытаться это обойти. Вы настроите отправляющую машину на отправку каждого пакета отдельно, но ваши пакеты могут сливаться и на транзитных узлах. Кстати, может быть и обратное, пакет может приходить по частям.
Делайте сразу правильно, поверьте, будет меньше проблем в дальнейшем. Улыбающийся

P.S. Кстати, у вас ошибки на принимающей стороне. Это будет работать в синтетических тестах и может (скорее всего будет) не работать на реальной сети.
« Последнее редактирование: Декабрь 19, 2013, 15:45 от Old » Записан
ploop
Гость
« Ответ #4 : Декабрь 19, 2013, 15:53 »

Вот, кстати, пример принимающего кода, ещё не отлаженный, но корректно работающий, если в сеть выплюнуть подряд несколько разнообразных пакетов от нескольких байт до сотен мегабайт.
Заголовок имеет такую структуру:
4 байта - размер блока
32 байта - хэш этого числа (размера), чтобы отсеять мусор. Иначе любой залётный байт на этот порт начнёт приниматься и разбираться. Я взял MD5, но можно что-нибудь попроще.
Далее - сам блок данных.
Код
C++ (Qt)
void tfrclient::slotReadyRead()
{
   // Чтение сокета
   QTcpSocket* pClientSocket = (QTcpSocket*)sender();
   QDataStream in(pClientSocket);
   in.setVersion(QDataStream::Qt_4_2);
 
   // Ждём приёма всего сообщения
   while(pClientSocket->bytesAvailable() > 0)
   {
       // Пока в буфере что-то есть, крутимся в цикле
       if ((pClientSocket->bytesAvailable() > sizeof(quint32)) &&
               (block_size == 0))
       {
           // Если количество байт в буфере больше 4х, и мы ещё не
           // забрали размер посылки, заберём этот размер
           QString md5;
           quint32 size;
           quint32 p1, p2;
           in >> size;
           p1 = pClientSocket->bytesAvailable();
           in >> md5;
           p2 = pClientSocket->bytesAvailable();
 
           if(md5 == getMd5(size))
           {
               block_size = size-(p1-p2);
               qDebug() << "size=" << block_size;
           }
       }
       if (block_size > 0)
       {
           // Если размер у нас есть, складываем всё в буфер
           // до тех пор, пока не примем всю посылку
           while((input_buf.size() < (int)block_size) && (pClientSocket->bytesAvailable() > 0))
           {
               // Забираем только ту часть пакета, которая указана в заголовке
               QByteArray tmp;
               quint32 size = (block_size > pClientSocket->bytesAvailable())
                       ? pClientSocket->bytesAvailable() : block_size;
               tmp.resize(size);
               in.readRawData(tmp.data(),size);
 
               input_buf.append(tmp);
           }
           qDebug() << "input_buf="<<input_buf.size()<<"NextBlock="<<block_size;
 
           if (input_buf.size() > (int)block_size)
           {
               qDebug() << "Error! Clean socket";
               pClientSocket->readAll();
               pClientSocket->reset();
               block_size = 0;
               input_buf.clear();
               return;
           }
 
           if (input_buf.size() == (int)block_size)
           {
               // Наш буфер заполнен, обрабатываем
               parse_buf(&input_buf);
               block_size = 0;
               input_buf.clear();
           }
           else
           {
               qDebug() << "Next loop!";
               return;
           }
       }
   }
}
Записан
Fregloin
Супер
******
Offline Offline

Сообщений: 1025


Просмотр профиля
« Ответ #5 : Декабрь 21, 2013, 14:22 »

ужасный код, не в обиду. во первых. во вторых вычислять хеш каждый раз на прием и отправку думаю будет накладновато, если конечно скорость не важна. в третьих статически преобразовывать sender к QTcpSocket можно, но лучще делать через qobject_cast.
ну и главное ваш код не будет работать с не Qt приложениями.
Записан
GPPsoft
Гость
« Ответ #6 : Декабрь 24, 2013, 11:47 »

Проблема еще актуальна?
Записан
ploop
Гость
« Ответ #7 : Январь 14, 2014, 12:34 »

ужасный код, не в обиду.
Писался на коленке, сейчас переписан полностью. Да и опыта у меня очень мало.
Цитировать
во вторых вычислять хеш каждый раз на прием и отправку думаю будет накладновато, если конечно скорость не важна
Не важна, у меня пакет раз в несколько минут.
Цитировать
ваш код не будет работать с не Qt приложениями.
Не актуально, но хотелось бы знать почему? Из-за сериализации через QDataStream? Так это и ежу понятно. Или Вы что-то ещё имели ввиду?
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


Надо улыбаться


Просмотр профиля
« Ответ #8 : Январь 15, 2014, 09:14 »

Из-за сериализации через QDataStream? Так это и ежу понятно.
Да это не такая уж проблема. Эта сериализация нормально документирована. Повторить её на другом языке в нужном объёме не такая уж и проблема.
Записан
Firefox
Гость
« Ответ #9 : Январь 15, 2014, 13:17 »

не хочу создавать новую тему, потому спрошу в этой. мне кажется что обмен, который я написала не очень хорош. потому хочу переписать.  и хочу спросить про само построение логики, чтоб обмен был логически лучше. вот старый пример сервера:
Код:
tripserver.h

#ifndef TRIPSERVER_H
#define TRIPSERVER_H


#include <QTcpServer>
#include <QTcpSocket>
#include <QApplication>

#include "clientsocket.h"
#include "common_gs.h"

#define port_pod 1111
//#define port_out_pod 1112

class QTcpServer;
class QTcpSocket;

class TripServer :  public QTcpServer

{
    Q_OBJECT

public:
    TripServer(QObject *parent = 0 );
     QTcpSocket   *socket_pod;
     QTcpSocket   *socket_2d_8d;
     QTcpSocket   *socket_sord_16KP;
     QTcpSocket   *socket_sord_toACHVO;
     QTcpSocket   *socket_sord_fromACHVO;
     ClientSocket *soc;

  signals:
     void sendData_pod();
     void sendData_sord();
     void sendData_2d_8d();
     void sendData_16KP(QString);
     void OTMData(int,int);
     void SignalRezim16KP(unsigned short,unsigned short);
     void BufferForSend(QByteArray);
     void IzzlOn(QByteArray);
public slots:
     void slotDisconnected_pod();
     void slotDisconnected_2d_8d();
     void slotDisconnected_16KP();
     void slotDisconnected_toACHVO();
     void slotDisconnected_fromACHVO();


private:
    void incomingConnection(int socketId);

Код:
tripserver.cpp


#include "tripserver.h"
TripServer::TripServer(QObject *parent)
    : QTcpServer(parent)
{
   soc=new ClientSocket(this);
   socket_pod=new QTcpSocket(this);
   socket_2d_8d= new QTcpSocket(this);
   socket_sord_16KP= new QTcpSocket(this);
   socket_sord_toACHVO= new QTcpSocket(this);
   socket_sord_fromACHVO= new QTcpSocket(this);
}

void TripServer::incomingConnection(int socketId)
{
    qDebug()<<this->serverPort();
   if( this->serverPort()==port_pod)// обмен СЃ "Подыгрышем РЎРІСЏР·Рё"
   {
        socket_pod->setSocketDescriptor(socketId);
        if(socket_pod)
        {
          soc->socket_out=socket_pod;
          connect(socket_pod,SIGNAL(readyRead()),soc,SLOT(readClient()));
          connect(socket_pod,SIGNAL(disconnected()),this,SLOT(slotDisconnected_pod()));
        }
   }

   if(this->serverPort()==_PORT_2D_8D)//обмен СЃ РЎРћР Р” РїРѕ протоколу 2Р”-8Р” РїСЂРёР±РѕСЂРѕРІ
   {
       socket_2d_8d->setSocketDescriptor(socketId);
       if(socket_2d_8d)
       {
            soc->socket_out=socket_2d_8d;
            connect(socket_2d_8d,SIGNAL(disconnected()),this,SLOT(slotDisconnected_2d_8d()));
            connect(this,SIGNAL(sendData_2d_8d()),soc,SLOT(slotsendData_2d_8d()));
            connect(socket_2d_8d,SIGNAL(readyRead()),soc,SLOT(readClientSord_2d_8d()));
            connect(soc,SIGNAL(SendData_2d_8d()),soc,SLOT(slotsendData_2d_8d()));
            connect(soc,SIGNAL(Radiation_on(QByteArray)),this,SIGNAL(IzzlOn(QByteArray)));
       }
   }
   if(this->serverPort()==_PORT_16KP) //обмен СЃ РЎРћР Р” РїРѕ протоколу 16РљРџ РїСЂРёР±РѕСЂР°
   {
       socket_sord_16KP->setSocketDescriptor(socketId);
       if(socket_sord_16KP)
       {
           soc->socket_out=socket_sord_16KP;
           connect(socket_sord_16KP,SIGNAL(disconnected()),this,SLOT(slotDisconnected_16KP()));
           connect(socket_sord_16KP,SIGNAL(readyRead()),soc,SLOT(readClientSord_16KP()));
           connect(soc,SIGNAL(SignalRezim(unsigned short,unsigned short)),this,SIGNAL(SignalRezim16KP(unsigned short,unsigned short)));
           connect(soc,SIGNAL(SignBufferForSend(QByteArray)),this,SIGNAL(BufferForSend(QByteArray)));
       }
   }
   if(this->serverPort()==_PORT_FROM_ACHVO) // обмен СЃ РЎРћР Р” РїРѕ протоколу АЧВО(отправка данных РІ АЧВО)
   {
       socket_sord_toACHVO->setSocketDescriptor(socketId);
       if(socket_sord_toACHVO)
       {
           soc->socket_out=socket_sord_toACHVO;
           connect(socket_sord_toACHVO,SIGNAL(disconnected()),this,SLOT(slotDisconnected_toACHVO()));
       }
   }
   if(this->serverPort()==_PORT_TO_ACHVO) // обмен СЃ РЎРћР Р” РїРѕ протоколу АЧВО(прием данных РѕС‚ АЧВО)
   {
       socket_sord_fromACHVO->setSocketDescriptor(socketId);
       if(socket_sord_fromACHVO)
       {
           soc->socket_out=socket_sord_fromACHVO;
           connect(socket_sord_fromACHVO,SIGNAL(disconnected()),this,SLOT(slotDisconnected_fromACHVO()));
           bool nn=connect(socket_sord_fromACHVO,SIGNAL(readyRead()),soc,SLOT(readClientSord_Achvo()));
           qDebug()<<"nn"<<nn;
       }
   }

}

void TripServer::slotDisconnected_pod()
{
    if(socket_pod)
       {
            socket_pod->disconnectFromHost();
            disconnect(socket_pod,SIGNAL(readyRead()),soc,SLOT(readClient()));
            disconnect(socket_pod,SIGNAL(disconnected()),this,SLOT(slotDisconnected_pod()));
            //disconnect(this,SIGNAL(sendData_pod()),soc,SLOT(slotsendData_pod()));
       }
}
void TripServer::slotDisconnected_2d_8d()
{
    if(socket_2d_8d)
    {
        socket_2d_8d->disconnectFromHost();
        disconnect(this,SIGNAL(sendData_2d_8d()),soc,SLOT(slotsendData_2d_8d()));
        disconnect(socket_2d_8d,SIGNAL(disconnected()),this,SLOT(slotDisconnected_2d_8d()));
        disconnect(socket_2d_8d,SIGNAL(readyRead()),soc,SLOT(readClientSord_2d_8d()));
        disconnect(soc,SIGNAL(SendData_2d_8d()),soc,SLOT(slotsendData_2d_8d()));
    }
}
void TripServer::slotDisconnected_16KP()
{
    if(socket_sord_16KP)
    {
        disconnect(socket_sord_16KP,SIGNAL(disconnected()),this,SLOT(slotDisconnected_16KP()));
        disconnect(socket_sord_16KP,SIGNAL(readyRead()),soc,SLOT(readClientSord_16KP()));
    }
}
void TripServer::slotDisconnected_toACHVO()
{
    if(socket_sord_toACHVO)
    {
       disconnect(socket_sord_toACHVO,SIGNAL(disconnected()),this,SLOT(slotDisconnected_toACHVO()));
    }
}
void TripServer::slotDisconnected_fromACHVO()
{
    if(socket_sord_fromACHVO)
    {
        disconnect(socket_sord_fromACHVO,SIGNAL(disconnected()),this,SLOT(slotDisconnected_fromACHVO()));
        disconnect(socket_sord_fromACHVO,SIGNAL(readyRead()),soc,SLOT(readClientSord_Achvo()));
    }
}

вызов класса в главном потоке
Код:
 serv=new TripServer(this);
    servSord_2d_8d=new TripServer(this);
    serverSord_16KP= new TripServer(this);
    serverSord_toAchvo=new TripServer(this);
    serverSord_fromAchvo=new TripServer(this);
    qDebug()<<"PORT_client_16KP"<<PORT_client_16KP;
    serv->listen(QHostAddress::Any,PORT_client_16KP);
    servSord_2d_8d->listen(QHostAddress::Any,_PORT_2D_8D);
    serverSord_16KP->listen(QHostAddress::Any,_PORT_16KP);
    serverSord_toAchvo->listen(QHostAddress::Any,_PORT_TO_ACHVO);
    serverSord_fromAchvo->listen(QHostAddress::Any,_PORT_FROM_ACHVO);

    //связь сигналов по пришедшим из теста данным с обработкой инф-и
    connect(serv->soc,SIGNAL(Sign_Sinhr(QString,QString,QString,QString,QString)),this,SLOT(slotATGS_Sinhr(QString,QString,QString,QString,QString)));
    connect(serv->soc,SIGNAL(Sign_NT()),this,SLOT(slotATGS_NT()));
    connect(serv->soc,SIGNAL(Sign_TLG(QString)),this,SLOT(slotATGS_TLG(QString)));
    connect(serv->soc,SIGNAL(Sign_KT()),this,SLOT(slotATGS_KT()));
    connect(serv->soc,SIGNAL(Sign_Pilot(QString,QString,QString)),this,SLOT(slotPilot(QString,QString,QString)));
    connect(serv->soc,SIGNAL(Sign_KK(QString)),this,SLOT(slotKK(QString)));
    connect(serv->soc,SIGNAL(Sign_SR()),this,SLOT(slotSR()));
............
сокет
Код:
#include <QtNetwork>
#include "clientsocket.h"

QString packetSeparator="|";
unsigned char numb_packet=0;
float oldPeriod=0.f;

QFile fp("1.txt");
QByteArray str_send;
ClientSocket::ClientSocket(QObject *parent)
    : QTcpSocket(parent)
{
    flag_write_data=true;
    nextBlockSize = 0;
    socket_out=new QTcpSocket(this);
    head.resize(4);
    head[0]=0xe0;
    head[1]=0xe3;
    head[2]=0xe5;
    head[3]=0xe7;
    count_packet_to16KP=0;
}

void ClientSocket::readClient()
{
    QTcpSocket  *socket_in=(QTcpSocket *)sender();
    QByteArray arrData;
    arrData.resize(0);
    QDataStream in(socket_in);
    in.setVersion(QDataStream::Qt_4_2);
    quint64 NextBlockSize=0;
    for(;;)
    {
        if(!NextBlockSize)
        {
            if((unsigned)socket_in->bytesAvailable()<sizeof(quint16))
                break;
            NextBlockSize=socket_in->bytesAvailable();
        }
        if((unsigned)socket_in->bytesAvailable()<=NextBlockSize)
            break;
    }
        arrData= socket_in->read(NextBlockSize);
        qDebug()<<"arrData"<<arrData;
        if(arrData.size()>=1)
        {
            QString pak=(QString)(arrData);
            qDebug()<<"arrData"<<arrData;
            QStringList List=pak.split(packetSeparator);
           ......
}
void ClientSocket::slotSendData_pod(QByteArray arr)
{
    int sz=0;
    if(socket_out->state()!=QAbstractSocket::ConnectedState)
        return;

      sz=socket_out->write(arr);
      socket_out->flush();

    if(sz!=arr.size())
    {
        qDebug()<<"SV_P: not all information writes to protocol";
    }
}



void ClientSocket::readClientSord_2d_8d()
{

    QTcpSocket  *socket_in=(QTcpSocket *)sender();
    QByteArray arrData;
    QDataStream in(socket_in);
    in.setVersion(QDataStream::Qt_4_2);
    quint64 NextBlockSize=0;
    NextBlockSize=socket_in->bytesAvailable();
    while(NextBlockSize>0)
    {
       arrData.append(socket_in->readAll());
       NextBlockSize=socket_in->bytesAvailable();
    }
    qDebug()<<"IN_Data_2D_8D"<<arrData;
   
    QString pak=(QString)(arrData);
    QStringList lst=pak.split('*');
    if(lst.size()>0)
         packetFrom2d_8d(lst);
}


хочу сделать такую модель, и спросить насколько она будет не ужасной.
Будет класс ExchangeConnection()- в него будет передаваться порт и IP адрес, внутри класса будет только подключение нового соединения по сигналу и слот по сигналу readyRead(). Потом несколько классов для каждого клиента, которые будут наследоваться от ExchangeConnection(), в этих классах будут задаваться порт и IP, передаваемые в ExchangeConnection() в конструкторе этих классов. а в самих классах уже будет идти разбор пакета от нужного клиента.
например
Код:
ExchangeConnection::ExchangeConnection(QObject *parent) :
    QObject(parent)
{
 tcpServer = new QTcpServer(this);
    connect(tcpServer,SIGNAL(newConnection()),this,SLOT(slot_new_connection()));
}
void ExchangeConnection::slot_new_connection()
{
    tcpClient = tcpServer->nextPendingConnection();
    connect(tcpClient,SIGNAL(disconnected()),this,SLOT(slot_disconnect()));
    connect(tcpClient,SIGNAL(readyRead()),this,SLOT(on_readyRead()));
}
void ExchangeConnection::slot_disconnect()
{
    tcpClient->deleteLater();
}
void ExchangeConnection::on_readyRead()
{
    if(!tcpClient)
        return;
    QByteArray arrData;
    QDataStream in(tcpClient);
    in.setVersion(QDataStream::Qt_4_2);
    quint64 NextBlockSize=0;
    NextBlockSize=socket_in->bytesAvailable();
// вопрос про правильность организации чтения????????
    while(NextBlockSize>0)
    {
       arrData.append(tcpClient->readAll());
       NextBlockSize=tcpClient>bytesAvailable();
    }

}

Подскажите как такая структура сервера?
« Последнее редактирование: Январь 16, 2014, 13:13 от Firefox » Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.211 секунд. Запросов: 22.