crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

5 страниц V   1 2 3 > »   
Ответить в данную темуНачать новую тему
> Обрыв соединения QTcpSocket
OrSOn
  опции профиля:
сообщение 16.2.2010, 14:47
Сообщение #1


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


Всем добрый день! Столкнулся с довольно неприятной проблемой при работе с сокетами... Суть проблемы в следующем:

Имеется сервер и клиент, для общения используют сокеты. В некий момент времени клиент рушится (ну или связь падает, не суть важно), при этом сервер пытается что-то писать в сокет, что приводит к ошибке. Чтобы избежать этого, пробовал ввести проверку

if( tcpSocket->state() != 3 )
    return;
tcpSocket->flush();


Так вот случаются ситуации, что проверка состояния проходит, а сразу после нее до начала проталкивания информации клиент падает и на tcpSocket->flush() снова вылетаю с ошибкой.

Если кто сталкивался с подобным, подскажите, пожалуйста, как это можно обойти...

Сообщение отредактировал OrSOn - 16.2.2010, 14:48
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
sploid
  опции профиля:
сообщение 16.2.2010, 17:29
Сообщение #2


Студент
*

Группа: Участник
Сообщений: 51
Регистрация: 26.2.2008
Из: Москва
Пользователь №: 106

Спасибо сказали: 10 раз(а)




Репутация:   1  


так в чем проблема? в том что сервер не знает записаны данные или нет?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
SABROG
  опции профиля:
сообщение 16.2.2010, 20:28
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 1207
Регистрация: 8.12.2008
Из: Russia, Moscow
Пользователь №: 446

Спасибо сказали: 229 раз(а)




Репутация:   34  


Цитата(OrSOn @ 16.2.2010, 14:47) *
вылетаю с ошибкой.


С какой именно и куда? Обрабатывать ошибку никак нельзя что ли?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 17.2.2010, 10:07
Сообщение #4


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


Обработать ошибку нельзя - полностью прерывается дебаг и вылетаю, ошибка получается в том, что я пытаюсь записать информацию в сокет, который имеет состояние disconnected(), причем это состояние он получает в процессе выполнения команды записи, т.е. заранее это не отследить. Грубо говоря, получается такая ситуация:

1. Сокет подключен, начинается запись (запускается стандартная функция Qt)
2. Прямо во время записи рвется соединение
3. Половина функции прошла, а во второй оказывается, что соединения нет и вылетает ошибка...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.2.2010, 10:15
Сообщение #5


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Цитата(OrSOn @ 17.2.2010, 10:07) *
Обработать ошибку нельзя - полностью прерывается дебаг и вылетаю, ошибка получается в том, что я пытаюсь записать информацию в сокет, который имеет состояние disconnected(), причем это состояние он получает в процессе выполнения команды записи, т.е. заранее это не отследить. Грубо говоря, получается такая ситуация:

1. Сокет подключен, начинается запись (запускается стандартная функция Qt)
2. Прямо во время записи рвется соединение
3. Половина функции прошла, а во второй оказывается, что соединения нет и вылетает ошибка...

Покажи код, как ты это делаешь. Никаких вылетов быть не должно.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 17.2.2010, 10:19
Сообщение #6


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


while( tmpLength < file.size() )
    {
        if( file.size() - tmpLength > blockLength )
            tmpBlock = blockLength;
        else
            tmpBlock = file.size() - tmpLength;

        char * dataBlock = new char[ tmpBlock ];

        file.read( dataBlock, tmpBlock );

        if( !tcpSocket || freeThread )
            return;
        else
            if( tcpSocket->state() != 3 )
                return;
        tcpSocket->write( dataBlock, tmpBlock );

        if( !tcpSocket || freeThread )
            return;
        else
            if( tcpSocket->state() != 3 )
                return;
        while( tcpSocket->flush() )
        {
            if( !tcpSocket || freeThread )
                return;
            else
                if( tcpSocket->state() != 3 )
                    return;
            continue;
        }

        delete []dataBlock;

        tmpLength += tmpBlock;
    }


Вот, это "тот самый" кусок примера... Как видно, уже везде, где только можно, включена проверка на разрывы

if( !tcpSocket || freeThread )
    return;
else
    if( tcpSocket->state() != 3 )
        return;


Тем не менее, на строке while( tcpSocket->flush() ) вылетает ошибка, потому что разрыв умудряется произойти во время выполнения...

З.Ы. чтобы не так нагромождено все было, вот изначальный код без проверок

while( tmpLength < file.size() )
    {
        if( file.size() - tmpLength > blockLength )
            tmpBlock = blockLength;
        else
            tmpBlock = file.size() - tmpLength;

        char * dataBlock = new char[ tmpBlock ];

        file.read( dataBlock, tmpBlock );

        tcpSocket->write( dataBlock, tmpBlock );

        while( tcpSocket->flush() )
            continue;

        delete []dataBlock;

        tmpLength += tmpBlock;
    }



Сообщение отредактировал OrSOn - 17.2.2010, 10:21
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.2.2010, 10:25
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Покажи как создается объект tcpSocket и какие сигналы обрабатываются.

Ты уверен, что этот объект не разрушается где-то еще (вижу там какой-то freeThread)?

Все эти проверки не нужны, ошибка где-то в другом месте.
У тебя течет память для буфера dataBlock, при любой ошибки - она не удаляется.
Зачем цикл у flush?

Сообщение отредактировал BRE - 17.2.2010, 10:27
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 17.2.2010, 10:34
Сообщение #8


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


Значит по порядку...
Объект создается нормально, но в другом классе (раньше все работало, пока я не стал разбивать файлы на блоки, т.е. когда файл отсылал целиком, никаких ошибок не было). Суть в следующем: есть управляющий класс,в нем QTcpServer. Когда поступает запрос подключения, создается сокет, затем он добавляется в очередь. А далее из очереди сокеты передаются в заранее созданные потоки на обработку, после чего возвращаются обратно в очередь.

Насчет не освобождается память - я в курсе, это не страшно в данном случае (ошибки от этого не возникнет), потом устраню, когда разберусь, где все рушится.

Цикл сделан тоже неспроста... Раньше было без него, но столкнулся с некоторой проблемой - длинные файлы просто не передавались целиком, т.е. часть файла принималась с клиентской стороны, а потом сигналы readyRead() просто переставали приходить, т.е. каким-то образом остатки файла не проталкивались, хотя сервер и уходил дальше в eventLoop... Да и не в этом проблема, он рушится даже на первом вызове... Вот и не могу понять, почему при неизменном коде все работало при отправке файлов целиком и стало рушится при разбиении на блоки...

И кстати, проверки, все же, нужны, но несколько для других целей - чтобы остановить выполнение функции после разрыва соединения, иначе будет путаница с данными, если этот сокет разорвался, а потоку дали другой на обработку... И новый сокет "завершит" действия, которые предназначались не ему.

Сообщение отредактировал OrSOn - 17.2.2010, 10:36
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
BRE
  опции профиля:
сообщение 17.2.2010, 10:50
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 1112
Регистрация: 6.3.2009
Из: Ростов-на-Дону
Пользователь №: 591

Спасибо сказали: 264 раз(а)




Репутация:   44  


Класс TcpSocket данные кеширует сам и отправляет их блоками. Происходит это в цикле обработки событий.

Ты не показал код..., но мне кажется, что при разрыве соединения сам объект на который указывает tcpSocket разрушается (например в другом потоке), и ты пытаешься использовать уже разрушенный объект.

Метод write возвращает размер реально записанных данных, не всегда все данные могут поместиться в буфер отправки TCP-стека (хотя Qt и кеширует их сам). Эту ситуацию так же нужно обрабатывать.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
OrSOn
  опции профиля:
сообщение 17.2.2010, 11:02
Сообщение #10


Студент
*

Группа: Участник
Сообщений: 46
Регистрация: 8.12.2009
Пользователь №: 1289

Спасибо сказали: 0 раз(а)




Репутация:   0  


Увы, но удаления объекта не происходит. Я уже думал об этом, поэтому тупо закомментировал ВСЕ места, где происходит удаление - результата нет. А насчет обработки записи, flush() записывает максимально возможное количество информации (не дожидаясь возвращения в цикл обработки событий), поэтому помещение его в цикл (пока записывается) как раз и осуществляет эту обработку (я уже проверял на файлах по 1.36 гигабайта). И если соединение не рвать, тов се работает и передается отлично, ломается только при закрытии клиента.

З.Ы. как говорит ассистант, мы не можем использовать flush() для сокетов, у которых состояние не connected(), так что рушится оно неспроста... А вот как обойти - хз.

З.З.Ы. код показать не могу, ибо там слишком много и все в разных классах... Но если конкретно создание сокета интересует, то вот оно:

 
if (tcpServer->hasPendingConnections()==FALSE)
        return;
    
tcpSocket = tcpServer->nextPendingConnection();
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readFortune()), Qt::QueuedConnection);
tcpSocket->reset();

tcpSocket->write((QString::number((int)((void *)tcpSocket))).toLocal8Bit());

tcpSocket->flush();

tmpSocketList.append( tcpSocket );


Это содержимое слота, который обрабатывает сигнал newConnection()

Сообщение отредактировал OrSOn - 17.2.2010, 11:05
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

5 страниц V   1 2 3 > » 
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 6.7.2022, 10:43