Russian Qt Forum

Qt => Работа с сетью => Тема начата: Гурман от Декабрь 26, 2013, 10:00



Название: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Гурман от Декабрь 26, 2013, 10:00
Надо передавать и принимать байты некоему устройству через LAN или физический порт принтера. Через порт принтера всё работает на ура. Через LAN с разбега не получилось. Вот код функций (то, что класс называется MainWindow пусть не смущает, приложение глухо консольное, просто так исторически сложилось).

собственно установка соединения:

Код:
bool MainWindow::EnableTransfer() // вызывается из конструктора MainWindow
{
if( ! ipusing )
{
qDebug( "Opening parallel port transfer... " );

h = CreateFileA( "\\\\.\\UserPort", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if( h == INVALID_HANDLE_VALUE )
{
qDebug ("Error: could not get parallel port access.\n");
return false;
}
}
else
{
bool converted = false;
unsigned int port = a->arguments().at(2).toUInt( &converted ); // QCoreApplication* a
if( ! converted )
{
qDebug ("Error: invalid port number.\n");
return false;
}

qDebug( "Opening TCP/IP transfer... (to use paraller port add LPT after program name) " );

if( ( socket = new QAbstractSocket( QAbstractSocket::TcpSocket, a ) ) == 0 )
{
qDebug ("Error: could not create connection.\n");
return false;
}

socket->connectToHost( a->arguments().at(1), port );

if( ! socket->waitForConnected( PortTimeOut ) )
{
qDebug ("Error: Connection timeout.\n");
return false;
}
}
qDebug( "Running normal\n" );
return true;
}

и чтение-запись байтов данных:
Код:
void MainWindow::outport( BYTE data )
{
if( ipusing )
{
if( ! socket->putChar( data ) )
{
qDebug( "Error: Network write error.\n" );
a->exit( -1 );
}
socket->flush();
}
else // LPT
{
__asm
(
"outb %%al, %%dx;"
   : // нет ничего
   : "d" (lpt_addr), "a" (data) // AX:данные, DX:адрес
);
}
}

BYTE MainWindow::inport()
{
if( ipusing )
{
char data;
if( ! socket->getChar( &data ) )
{
qDebug( "Error: Network read error.\n" );
a->exit( -1 );
return -1;
}
return data;
}
// else LPT
__asm
(
"inb %%dx, %%al;"
   : // возврат в AX
   : "d" (lpt_addr+1) // DX:адрес AX:данные
);
// return уже на месте
}

Устройство открывается, сетевых ошибок нет, байты по сети в него улетают, ошибок передачи тоже нет, но при приеме ответа прилетает белиберда, чаще 0, иногда нет. Но совсем не то, что ожидается. Конечно, могут быть ошибки при передаче самим устройством. Через параллельный порт работает всё правильно, то есть устройство правильно формирует ответные данные - ошибки могут быть в реализации сетевых функций на устройстве. Или - может есть какие-то тонкости при работе с сокетами в Qt? Кто опытный в реализации подобного обмена - подскажите.


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Old от Декабрь 26, 2013, 10:18
А почему создаете QAbstractSocket вместо QTcpSocket?


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Гурман от Декабрь 26, 2013, 10:33
А почему создаете QAbstractSocket вместо QTcpSocket?

а какая разница? у QTcpSoclet нет своих методов, это просто враппер над QAbstractSocket

Код:
//#define QTCPSOCKET_DEBUG
/*!
\class QTcpSocket
\brief The QTcpSocket class provides a TCP socket.
\reentrant
\ingroup io
\inmodule QtNetwork
TCP (Transmission Control Protocol) is a reliable,
stream-oriented, connection-oriented transport protocol. It is
especially well suited for continuous transmission of data.
QTcpSocket is a convenience subclass of QAbstractSocket that
allows you to establish a TCP connection and transfer streams of
data. See the QAbstractSocket documentation for details.
\bold{Note:} TCP sockets cannot be opened in QIODevice::Unbuffered mode.
\sa QTcpServer, QUdpSocket, QFtp, QNetworkAccessManager,
{Fortune Server Example}, {Fortune Client Example},
{Threaded Fortune Server Example}, {Blocking Fortune Client Example},
{Loopback Example}, {Torrent Example}
*/
#include "qlist.h"
#include "qtcpsocket_p.h"
#include "qtcpsocket.h"
#include "qhostaddress.h"
QT_BEGIN_NAMESPACE
/*!
Creates a QTcpSocket object in state \c UnconnectedState.
\a parent is passed on to the QObject constructor.
\sa socketType()
*/
QTcpSocket::QTcpSocket(QObject *parent)
: QAbstractSocket(TcpSocket, *new QTcpSocketPrivate, parent)
{
#if defined(QTCPSOCKET_DEBUG)
qDebug("QTcpSocket::QTcpSocket()");
#endif
d_func()->isBuffered = true;
}
/*!
Destroys the socket, closing the connection if necessary.
\sa close()
*/
QTcpSocket::~QTcpSocket()
{
#if defined(QTCPSOCKET_DEBUG)
qDebug("QTcpSocket::~QTcpSocket()");
#endif
}
/*!
\internal
*/
QTcpSocket::QTcpSocket(QTcpSocketPrivate &dd, QObject *parent)
: QAbstractSocket(TcpSocket, dd, parent)
{
d_func()->isBuffered = true;
}
QT_END_NAMESPACE


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Old от Декабрь 26, 2013, 10:42
а какая разница?
Ну как-бы это сейчас может нет разницы, а дальше (в следующих версиях Qt) она может появиться. :)

Попробуйте вначале дождаться данных: waitForReadyRead или ожиданием сигнала.



Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Гурман от Декабрь 26, 2013, 15:40
а какая разница?
Ну как-бы это сейчас может нет разницы, а дальше (в следующих версиях Qt) она может появиться. :)

меня интересует исключительно сейчас :D

Попробуйте вначале дождаться данных: waitForReadyRead или ожиданием сигнала.

а без разницы - что socket->getChar( &data ) вернет ошибку, потому что данных нет, что будет ожидание - не приходят они...


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Old от Декабрь 26, 2013, 16:13
не приходят они...
Остается поснифать сетевой трафик и посмотреть что происходит.


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Гурман от Декабрь 27, 2013, 07:54
То есть, у меня в коде всё правильно, и никаких тонкостей, которые я бы упустил, у QAbstractSocket нет?


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Bepec от Декабрь 27, 2013, 08:24
Оригинально только чтение по одному байту, а не всего пришедшего пакета.

Посоветовал бы сделать тестовый вариант программы для устройства, посылающей инкрементируемый счётчик в цикле по сокету.

Тогда сразу можно будет сказать где проблема.


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Гурман от Декабрь 27, 2013, 09:26
а устройство посылает и принимает байты, если делать обмен пакетами, то надо прошивку устройства переделывать


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Bepec от Декабрь 27, 2013, 10:02
Получаете пакет, потом пересылаете устройству по одному. Где проблема?

Ну переделайте прошивку в болванку, которая эхо генерирует. Я не думаю, что это сложно.

PS а как вы вообще разрабатываете под устройство, если не проверяете систему связи?


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Гурман от Декабрь 27, 2013, 10:30
вот это и есть проверка

получать пакет нет смысла, обмен идет по одному байту - передача-прием-передача-прием, то есть, команда-ответ-команда-ответ...

добавил задание размера буфера в 1 байт, и ожидание его заполнения - получаю таймаут...

ну ясно, в общем, придется нашим друзьям ковырять прошивку, очевидно, дело всё-таки, в ней


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Bepec от Декабрь 27, 2013, 10:57
WireShark скачайте и посмотрите, что от устройства и к устройству идёт. Будет гораздо лучше вам и вашим друзьям, если вы увидите - устройство что-то посылает, или нет.

WireShark так же покажет, если придёт некорректная информация. И будет уже на что опираться. То ли молчит, то ли говорит не по протоколу :)


Название: Re: QAbstractSocket - хочется уточнить возможные тонскости
Отправлено: Гурман от Декабрь 27, 2013, 11:02
WireShark скачайте и посмотрите

это, кстати, дело...


Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Гурман от Январь 10, 2014, 08:08
Приходится поднять тему... С помощью сторонней программы установили, что связь с устройством работает - в него прошили простой loopback, посылающий на выход то, что оно получает. И отдельная софтина на Борланде нормально получает то, что послала. Но код на Qt, который выше - банан. Соединение есть, дополнительные проверки

Код:
		if( ! socket->isValid() )
{
qDebug ("Error: Socket is not valid.\n");
return false;
}
if( ! socket->isOpen() ) // MUST be opened before
{
if( ! socket->open( QIODevice::ReadWrite ) )
{
qDebug ("Error: Socket is not open.\n");
return false;
}
}

ничего не дали - сокет валидный, открытый. Функция передачи putChar() ошибку не возвращает. Но при чтении getChar() ошибка. А если перед ней waitForReadyRead(), то всегда таймаут. Без ожидания готовности докопался до ошибки getChar() - Error: Network read error: Invalid socket descriptor.  ??? Как это? Почему инвалид? Только что туда запись была, всё было валид.  :( Сокет никто не закрывал, вообще с ним ничего не делал, кроме записи. И причем - если последовательно писать и читать несколько раз, то каждая запись проходит без ошибки, но каждое чтение возвращает ошибку. Как это может быть? На всякий случай явно указал, хотя это по дефолту:

socket->connectToHost( a->arguments().at(1), port, QIODevice::ReadWrite );

разумеется, не помогло.

Проверил значение дескриптора сокета после открытия и при чтении - всё нормально, значение совпадает. При чтении состояние Connection established. Что вообще не так?



Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Bepec от Январь 10, 2014, 09:36
Как вариант привести сюда программу на борланде. Посмотрим, сравним.

PS хотя некорректный сокет это плохо. Может в борланде где то инициализация какая нибудь происходит?


Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Гурман от Январь 10, 2014, 09:57
Как вариант привести сюда программу на борланде. Посмотрим, сравним.

PS хотя некорректный сокет это плохо. Может в борланде где то инициализация какая нибудь происходит?

Ну программу на борланде сюда - это нереально и не за чем. Я её сам посмотрел, там ничего военного. Никаких особых инициализаций, всё прозрачно. Правда, её на другой машине запускали. У меня стоит Касперский, фаервол включен, я в нем настроил доступ везде для своей программы, но ничего не изменилось. Сисадмин говорит, больше нигде никаких фаерволов нет.





Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Гурман от Январь 10, 2014, 10:32
разобрались с затыком... мастера прошивки проворные поменяли порт и не сказали никому  >:(

но все равно странно происходит - посылаю байт, там просто петля, его тут же отправляют обратно - я получаю, но с задержкой и ошибками при приеме (первый байт переданный, второй принятый):

Error: Network read error: Invalid socket descriptor 1608 state 3
0xff 0xff

Error: Network read error: Invalid socket descriptor 1608 state 3
0x0 0xff
0x1 0xff
0x2 0x0

Error: Network read error: Invalid socket descriptor 1608 state 3
0x3 0xff
0x4 0x1
0x5 0x2
0x6 0x3

Error: Network read error: Invalid socket descriptor 1608 state 3
0x7 0xff
0x8 0x4
0x9 0x5
0xff 0x6

причем места ошибок плавают. Может быть 1 на цикл, может быть 2, может 3.


Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Гурман от Январь 10, 2014, 10:51
хабы такие хабы...

я как-то ожидал, что getChar() дожидается, пока в буфере что-то не появится


Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: AJloff от Январь 14, 2014, 11:20
А почему создаете QAbstractSocket вместо QTcpSocket?


Название: Re: QAbstractSocket - хочется уточнить возможные тонкости
Отправлено: Гурман от Январь 17, 2014, 14:09
не помню уже... всё уже давно работает как надо