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

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

Страниц: [1] 2 3   Вниз
  Печать  
Автор Тема: Не всегда приходят данные QTCpSocket  (Прочитано 20183 раз)
Firefox
Гость
« : Февраль 26, 2014, 08:18 »

Здравствуйте. Хочу спросить про следующее: у меня есть сервер на другой программе клиент. клиент отправляет в сервер некий набор символов(не большой умещается в один пакет), сервер в ответ присылает код получения пакета. Так например при определенном действии клиент отправляет несколько пакетов, то есть 5, смысл того, что клиент отправляет пакет получает ответ и сразу же отправляет следующий пакет и опять ждет ответ(так 5 пакетов подряд). если он не получил один из ответов то далее не шлет пакет свой следующий. Загвозка в том, что если я ставлю точку останова в слот slot_readyRead()(генерится по сигналу readyRead()) на сервере, или при записи на клиенте, то все работает чудесно и все 5 пакетов доходят. если запускать без точки останова, то второй пакет от клиента записывается в сеть, а на сервере сигнал readyRead() не генерируется, и вся цепочка останавливается, так как клиент ждет подтверждения получения пакета, а сервер не видит сам пакет. Работаю в Windows 7. Подскажите в чем может быть причина такого поведения. Увеличить время до отправки пакета на клиенте или кидать постоянно в сеть пакеты до получения ответа не могу, так как программа написана другим человеком и уже закончена и не корректируется. Могу менять только на стороне сервера.
Записан
Bepec
Гость
« Ответ #1 : Февраль 26, 2014, 08:30 »

Увеличь буфер сокета, если данных много.
Записан
Firefox
Гость
« Ответ #2 : Февраль 26, 2014, 08:42 »

увеличила в 10 раз размер буфера на стороне сервера, если я правильно поняла, но проблему так это и не решило, сигнал readyRead() не пришел потому до чтения ещё не добрались
Код:
 quint64 ReadDataSize=socket->read(dataPacket,(LenthPacket+1)*10);
« Последнее редактирование: Февраль 26, 2014, 08:51 от Firefox » Записан
OKTA
Гость
« Ответ #3 : Февраль 26, 2014, 09:12 »

Нужен код  Улыбающийся
Записан
LisandreL
Птица говорун
*****
Offline Offline

Сообщений: 984


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


Просмотр профиля
« Ответ #4 : Февраль 26, 2014, 09:32 »

Вы в курсе, что TCP - это протокол потоковой передачи данных и никак не гарантирует сохранения границ пакетов (может склеивать или нарезать их по своему усмотрению)?
То есть например вы быстро отсылаете 5 своих маленьких пакетов, TCP упаковывает их все в 1 пакет и сигнал readyRead() будет всего 1 (и все данные сразу доступны).
Записан
OKTA
Гость
« Ответ #5 : Февраль 26, 2014, 09:35 »

Вы в курсе, что TCP - это протокол потоковой передачи данных и никак не гарантирует сохранения границ пакетов (может склеивать или нарезать их по своему усмотрению)?
То есть например вы быстро отсылаете 5 своих маленьких пакетов, TCP упаковывает их все в 1 пакет и сигнал readyRead() будет всего 1 (и все данные сразу доступны).

я как понял, там жестко отсылается по одному пакетику и следующий отправляется только по приходу подтверждения.
Записан
Firefox
Гость
« Ответ #6 : Февраль 26, 2014, 09:42 »

поняли вы правильно.
вот код сервера
Код:
//ModulExchange .h
#ifndef MODULEEXCHANGE_H
#define MODULEEXCHANGE_H

#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QStringList>
#include "common_gs.h"
class ModuleExchange : public QObject
{
    Q_OBJECT
public:
    explicit ModuleExchange(QObject *parent = 0);
    int portInput;
    _PAR_SORD parFromSord; // структура для записи текущих параметров
    QByteArray head; // Заголовок пакета 0xe0,0xe3,0xe5,0xe7
    // установка порта на прослушивание
    void setPort(int port);
    // отправка данных
    void PacketSend(QByteArray);
    bool _connected;
   
signals:
    // есть соединение по определенному порту
    void connected();
    // нет соединения по конкретному порту
    void disconnected();
   
public slots:
    // включение или отключение прослушки отпределенного порта на сервере.
    void setEnableInput(bool _enable);
    // новое соединение
    void slot_new_connection();
    // пришел сигнал разрыва соединения
    void slot_disconnected();


     //слот чтения пакета
    void slot_readyRead();
protected:
    QTcpServer *server;
    QTcpSocket * socket;

    virtual void parsePacket(QByteArray _packet);

   
};
}

Код:
Modulexchange.cpp

#include "moduleexchange.h"
const QString packetSeparator="|";
const QString endSeparator="*";
ModuleExchange::ModuleExchange(QObject *parent) :
    QObject(parent)
{

     server= new QTcpServer(this);
     connect(server, SIGNAL(newConnection()),SLOT(slot_new_connection()));
     portInput=0;
     _connected=false;

     head.resize(4);
     head[0]=0xe0;
     head[1]=0xe3;
     head[2]=0xe5;
     head[3]=0xe7;

}
void ModuleExchange::slot_new_connection()
{
    socket=server->nextPendingConnection();
    connect(socket,SIGNAL(disconnected()),this, SLOT(slot_disconnected()));
    connect(socket,SIGNAL(readyRead()),this, SLOT(slot_readyRead()));
    _connected=true;
}
void ModuleExchange::slot_disconnected()
{
    socket->deleteLater();
}
void ModuleExchange::setPort(int port)
{
    portInput=port;
}
void ModuleExchange::setEnableInput(bool _enable)
{
    if(portInput==0)
        return;
    if(_enable)
    {
        server->listen(QHostAddress::Any,portInput);
    }
    else
    {
        server->close();
    }
}

void ModuleExchange::slot_readyRead()
{
    if(!socket)
        return;

    quint64 NextBlockSize=0;
    QByteArray Packet;
    NextBlockSize=socket->bytesAvailable();
    if(NextBlockSize<1)
        return;
    char dataP[NextBlockSize];
    Packet.clear();
    quint64 LenthPacket=0;
    socket->peek(dataP,NextBlockSize);
    Packet.setRawData(dataP,NextBlockSize);
    // номер в строке конца пакета("*")
    // для всех протоколов обмена кроме протокола с прибором 16
    if((LenthPacket=Packet.indexOf(endSeparator))>0 && LenthPacket<=NextBlockSize)
    {
       // есть конец пакета
        char dataPacket[LenthPacket];
        quint64 ReadDataSize=socket->read(dataPacket,(LenthPacket+1));
        Packet.setRawData(dataPacket,LenthPacket);
        parsePacket(Packet);
        if(ReadDataSize<NextBlockSize)
        {
            slot_readyRead();// принято больше данных чем должно быть в одном пакете
        }
    }
    // наличие заголовка пакета при обмене с 16 прибором
    else if(Packet.contains(head))
    {
        //ДОДЕЛАТЬ НЕ ВЕРНО ЕСЛИ ПАКЕТ ПРИХОДИТ ЗА 2 РАЗА, ТО У ВТОРОГО НЕТ ЗАГОЛОВКА
        char dataPacket[LenthPacket];
        quint64 ReadDataSize=socket->read(dataPacket,NextBlockSize);
        Packet.setRawData(dataPacket,NextBlockSize);
        parsePacket(Packet);
        if(ReadDataSize<NextBlockSize)
        {
            slot_readyRead();// не все данные считаны из канала
        }
    }
    else
    {
        slot_readyRead(); // в пакете нет символа конца пакета и заголовка,
                          //т.е. меньше данных чем должно быть
                          //или данные не соответствуют протоколам
    }
}
void ModuleExchange::parsePacket(QByteArray _packet)
{
;
}
void ModuleExchange::PacketSend(QByteArray _packet)
{
    if(!_connected)
        return;
    if(socket->state()!=QAbstractSocket::ConnectedState)
        return;
     int sz=socket->write(_packet,_packet.size());
     if(sz!=_packet.size())
    {
        qDebug()<<"not all information writes to protocol";
    }
}

Разбор пакета от нужного клиента

Код:
.h
#ifndef STRUCTURAEXCHANGE2D8D_H
#define STRUCTURAEXCHANGE2D8D_H

#include <QObject>
#include <QSettings>

#include "moduleexchange.h"

class StructuraExchange2D8D : public ModuleExchange
{
    Q_OBJECT
public:
    explicit StructuraExchange2D8D(QObject *parent = 0);
    QSettings *seting;
    void SendData_2d_8d(QByteArray _pack);
   
signals:
    void Radiation_on(QByteArray);// включено излучение на отправку АТГС данных в сорде
public slots:

protected:
    void parsePacket(QByteArray _packet);
   
};

#endif // STRUCTURAEXCHANGE_H
Код:
.cpp
#include "structuraexchange_2D8D.h"
//#include "/Structure/Structure.h"
#define packetSeparator "|"

StructuraExchange2D8D::StructuraExchange2D8D(QObject *parent) :
    ModuleExchange(parent)
{
    seting= new QSettings(
        tr("net.ini"),
        QSettings::IniFormat,
        this );
    seting->beginGroup("NET_PORT");
    int PORT=seting->value("_PORT_2D_8D", QString("")).toInt();
    qDebug()<<"PORT_client_2D8D"<<PORT;
    seting->endGroup();
    setPort(PORT);
    setEnableInput(true);
}
void StructuraExchange2D8D::parsePacket(QByteArray _packet)
{
   QByteArray arrData;
   arrData.resize(0);
   qDebug()<<"_packet from 28D"<<_packet;
   if(_packet.size()>=1)
   {
         QString str;
         str=QString::fromAscii(_packet);
         str=_packet.mid(0,2);
       
         if(str=="@C")
         {
             _packet=_packet.right(3);
             _packet=_packet.left(2);
             switch(_packet.toShort())
             {
                 case 0: parFromSord.Mos=0;break;
                 case 1: parFromSord.Mos=2;break;
                 case 4: parFromSord.Mos=3;break;
                 default: break;
             }
              SendData_2d_8d("@Y*");
         }
         if(str=="@U")
         {
              SendData_2d_8d("@Y*");
         }
         if(str=="@I")
         {
           emit SendData_2d_8d("@I");
         }
         if(str=="@A")
         {
              SendData_2d_8d("@A8F*");
         }
         if(str=="#M" )
         {
             _packet=arrData.right(2);
             _packet=arrData.left(1);

             switch(_packet.toShort())
             {
                 case 1:
                 parFromSord.Nap=2;
                 break;  // НИЗ
                 case 3:
                 parFromSord.Nap=3;
                 break;  // верх
                 default: break;
             };
             SendData_2d_8d("#Y*");
         }
         if(str=="#D" || str=="#U" )
         {
              SendData_2d_8d("#Y*");
         }
         if(str=="#R")
         {
             SendData_2d_8d("#Y*");
             emit Radiation_on(_packet.mid(2,1));
         }

     }

}

void StructuraExchange2D8D::SendData_2d_8d(QByteArray _pack)
{
     PacketSend(_pack);
     qDebug()<<"Packet_sent_2D_8D"<<_pack;
}
« Последнее редактирование: Февраль 26, 2014, 09:48 от Firefox » Записан
Firefox
Гость
« Ответ #7 : Февраль 26, 2014, 09:43 »

функция отправки данных на клиенте
Код:
void work_2d_8d::send_2d_8d( QString command )
{
static int shp=0;
QByteArray out;
QDataStream data_out( &out, QIODevice::WriteOnly );
data_out.setVersion( QDataStream::Qt_4_2 );
QByteArray command_asci;
command=command.toUpper();
command_asci=command.toAscii();

    data_out.writeRawData((char*)command_asci.data(), command_asci.size());
int sz=0;
    out.resize(out.size()*100);
sz=m_pTcpSocket->write( out );
    qDebug()<<"command28D_OUT"<<out<<"sz"<<sz;
    m_pTcpSocket->flush();
QString str_deb;
str_deb.sprintf( "%3d send: ", shp%1000 );
QString str;
for (int i=0; i<sz; i++ )
{
str.sprintf("%x ", (char)out[i] );
str_deb+=str;
}
emit type_data_signal( nPort, command+"  "+str_deb );

shp++;
}
Записан
OKTA
Гость
« Ответ #8 : Февраль 26, 2014, 10:03 »

1. А как определяете, что пакет второй точно отправляется с клиента?
2. А повторный вызов slot_new_connection() не происходит случайно?
Записан
Firefox
Гость
« Ответ #9 : Февраль 26, 2014, 10:21 »

1) ну я просто распечатала сам пакет и размер отправленных данных совпадает с размером пакета, и потом когда я работаю с точками останова я вижу что ко мне этот пакет приходит.
sz=m_pTcpSocket->write( out );
    qDebug()<<"command28D_OUT"<<out<<"sz"<<sz;!!!!!!

2) соединений генерится столько сколько клиентов подключается. вроде должно быть на каждый по одному
Записан
OKTA
Гость
« Ответ #10 : Февраль 26, 2014, 10:36 »

1) ну я просто распечатала сам пакет и размер отправленных данных совпадает с размером пакета, и потом когда я работаю с точками останова я вижу что ко мне этот пакет приходит.
sz=m_pTcpSocket->write( out );
    qDebug()<<"command28D_OUT"<<out<<"sz"<<sz;!!!!!!

2) соединений генерится столько сколько клиентов подключается. вроде должно быть на каждый по одному

1. Write не отправляет данные, а записывает во внутренний буфер сокета и не говорит ничего о факте непосредственной отправки данных.
2. Ну это да, но указатель на сокет используется один для всех - мало ли - проверьте)
3. Не знаю влияет ли, но может убрать рекурсивные вызовы слота slot_readyRead()? Он сам вызовется, когда будут данные  - незачем его дергать просто так вручную.
Записан
Firefox
Гость
« Ответ #11 : Февраль 26, 2014, 10:57 »

что может точно говорить о непосредственной отправке данных. чтобы они были видны для сокета на стороне сервера?
слот рекурсивно вызывается но в данном случае туда не заходит программа, то есть зацикливания нет, а вызывается от чтобы если придут за раз несколько пакетов по одному считывать из сети и отправлять в обработку.
Записан
OKTA
Гость
« Ответ #12 : Февраль 26, 2014, 11:09 »

На сколько я помню, можно судить по void QIODevice::bytesWritten ( qint64 bytes ) [signal].
А разве вы считываете по одному пакету? В слоте вы читаете сразу все доступные байты и потом уже парсите, на сколько я понял по коду.
Так же для отладки сокетов мне было удобно следить за сменой их состояний по void QAbstractSocket::stateChanged ( QAbstractSocket::SocketState socketState ) [signal].
Записан
Firefox
Гость
« Ответ #13 : Февраль 26, 2014, 11:15 »

попробую посмотреть спасибо, а считываю я по одному пакету, до символа "*" - это признак конца пакета, фенкция peek не считывает, данные после неё остаются в канале.
Записан
OKTA
Гость
« Ответ #14 : Февраль 26, 2014, 11:23 »

Да, пардон, пропустил.
И конечно следите за ошибками сокета! Проблема может быть совсем в другом, но лишним это в любом случае не будет и в отладке тоже поможет!
Записан
Страниц: [1] 2 3   Вверх
  Печать  
 
Перейти в:  


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