Название: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 22:07 Добрый вечер всем.У меня возникла следующая проблема.Создаю сервер.Новые сокеты выношу в отдельные потоки.Делаю это в общем то как принято,через дескрипторы:
void socket_thread::run() { if (!socket->setSocketDescriptor(descriptor)) { emit signalSocketError(socket->peerAddress().toString(),"error"); return; } com=new socket_coming(socket); connect(...); exec(); } Класс socket_coming - мой класс,в котором я произвожу все действия с сокетом,там же есть коннект на дисконнект сокета,и в слоте,который врубается на дисконнект пишу delete socket; т.е удаляю объект сокета.При этом после нескольких(примерно 10) дисконектов прога падает.Если убрать строчку удаления все работает,но память растет,и иногда вылетает ошибка QSocketNotifier: Multiple socket notifiers for same socket 2752 and type Read Я так понимаю,я не правильно удаляю сокет.В чем может быть проблема? Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 22:25 Ты в слоте, который вызывается сигналом сокета, его удаляешь?
Побольше кода покажи. Попробуй вместо удаления использовать: Код
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 22:31 Да.Насчет deleteLater пробовал,как понимаю,он не удаляет,память не освобождается.
по поводу кода приведу фрагмент из того класса: socket_coming::socket_coming(QTcpSocket *soc):QObject(),socket(soc) { //тут коннекты на сигналы от сокета,в том числе и дисконнект connect(...); connect(...); } //А это тот самый слот на дисконнект void socket_coming::slotDisconnected() { disconnect(..); disconnect(..); delete socket; emit socketDisconnected(); } сам объект этого класса,который создается в классе потока тоже в конце удаляю в деструкторе.В этом классе тоже ставил удаление сокета в деструктор-разницы нет Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 22:38 Боюсь спросить, это программа управления нашей орбитальной группировкой? ;)
Можно по-подробней? Это выглядит примерно так? Код Т.е. ты пытаешься разрушить сокет из обработчика его же сигнала? Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 22:43 ;)не совсем.
Да,ты прав,но удаление я ведь ставил и в деструктор класса.все равно прога падала. Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 22:46 В каком потоке создается объект QTcpSocket?
Как он передается в поток? Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 22:53 Спасиб большое :)
перенес эти строки в run socket=new QTcpSocket; socket->moveToThread(this); терь вроде все ок,еще раз большое спасиб :) Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 22:56 Спасиб большое :) Если создаешь в run, то это уже контекст этого потока. moveToThread излишен.перенес эти строки в run socket=new QTcpSocket; socket->moveToThread(this); терь вроде все ок,еще раз большое спасиб :) Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 22:58 Да,эм...кажись проблема не решилась :) ночью чтот голова плохо работает :)так вот,сам сокет создается в главном потоке,а передается вот так:
void socket_thread::run() { socket=new QTcpSocket; socket->moveToThread(this); if (!socket->setSocketDescriptor(descriptor)) { emit signalSocketError(socket->peerAddress().toString(),"error"); return; } com=new socket_coming(socket); } Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 23:00 Покажи код. :)
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 23:06 код из главного потока:
void main_widget::slotComingNewConnection() { coming_socket=serverComing->nextPendingConnection(); updateActiveTerminals(); socket_thread *sock_thread=new socket_thread(coming_socket->socketDescriptor()); connect(sock_thread,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateComingTerminalsList(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearComingTerminalsList(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalComingReadyWrite(QString)),this,SLOT(slotCreateOutGoing(QString)),Qt::QueuedConnection); connect(this,SIGNAL(signalWriteComing(QString,QString)),sock_thread,SLOT(slotComingWrite(QString,QString))); connect(sock_thread,SIGNAL(signalCloseThread(QString)),this,SLOT(slotBeforeCloseSocket(QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalSocketError(QString,QString)),this,SLOT(slotComingSocketError(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalCloseThread()),sock_thread,SLOT(quit()),Qt::QueuedConnection); sock_thread->start(); } код из потока: socket_thread::socket_thread(int descr):QThread() { descriptor=descr; } void socket_thread::run() { socket=new QTcpSocket; socket->moveToThread(this); if (!socket->setSocketDescriptor(descriptor)) { emit signalSocketError(socket->peerAddress().toString(),"error"); return; } com=new socket_coming(socket); connect(com,SIGNAL(socketReadyWriteSignal(QString)),this,SLOT(slotComingReadyWrite(QString))); connect(this,SIGNAL(signalComingWrite(QString,QString)),com,SLOT(slotWrite(QString,QString))); connect(com,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateTerminals(QString,QString))); connect(com,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearTerminals(QString,QString))); connect(com,SIGNAL(signalError(QString,QString)),this,SLOT(slotSocketError(QString,QString))); connect(com,SIGNAL(socketDisconnected()),this,SLOT(closeThread()),Qt::DirectConnection); exec(); } void socket_thread::closeThread() { disconnect(com,SIGNAL(socketReadyWriteSignal(QString)),this,SLOT(slotComingReadyWrite(QString))); disconnect(this,SIGNAL(signalComingWrite(QString,QString)),com,SLOT(slotWrite(QString,QString))); disconnect(com,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateTerminals(QString,QString))); disconnect(com,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearTerminals(QString,QString))); disconnect(com,SIGNAL(signalError(QString,QString)),this,SLOT(slotSocketError(QString,QString))); disconnect(com,SIGNAL(socketDisconnected()),this,SLOT(closeThread())); delete com; emit signalCloseThread(ip_address); emit signalCloseThread(); } код из класса socket_coming: socket_coming::socket_coming(QTcpSocket *soc):QObject(),socket(soc),val("") { connect(socket,SIGNAL(readyRead()),this,SLOT(slotReadyRead())); connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slotSocketError(QAbstractSocket::SocketError))); connect(socket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); } void socket_coming::slotDisconnected() { disconnect(socket,SIGNAL(readyRead()),this,SLOT(slotReadyRead())); disconnect(socket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); emit socketDisconnected(); } socket_coming::~socket_coming() { delete socket; } Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 23:11 Это не смущает? ;)
Код
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 23:19 :) :)смущает,убрал,поставил в деструктор потока,и пробывал ставить после exec(); все работает,прога не падает,но память растет.не знаете случайно почему?
Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 23:23 :) :)смущает,убрал,поставил в деструктор потока,и пробывал ставить после exec(); все работает,прога не падает,но память растет.не знаете случайно почему? Код А где удаление объекта sock_thread? Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 29, 2009, 23:37 ок,тогда можно глупый вопрос.как реализовать его удаление?я вот щас попытался сделать чтот типа такого
connect(sock_thread,SIGNAL(terminated())),sock_thread,SLOT(deleteLater())); ну естестно не сработало. Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 29, 2009, 23:39 ок,тогда можно глупый вопрос.как реализовать его удаление?я вот щас попытался сделать чтот типа такого Почему terminated?connect(sock_thread,SIGNAL(terminated())),sock_thread,SLOT(deleteLater())); ну естестно не сработало. Нитка нормально завершается, нужно использовать finished. Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 00:00 :)прогресс,терь память после дисконнекта освобождается,но ток на половину того,что занималось на этот поток.т.е при создании увеличение 0.2 мб,а при дисконнекте уменьшение на 0.1
Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 00:02 :)прогресс,терь память после дисконнекта освобождается,но ток на половину того,что занималось на этот поток.т.е при создании увеличение 0.2 мб,а при дисконнекте уменьшение на 0.1 Осталось удалять объект socket и думаю все будет нормально.Его можно создавать на стеке: Код
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 00:16 Да,ток хотел добавить что это скорее всего происходит из за того что не удаляю этот объект.Ок,а я вот пробывал удалить таким образом:
connect(this,SIGNAL(finished()),socket,SLOT(deleteLater())); почему этот вариант не катит? Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 00:24 Да,ток хотел добавить что это скорее всего происходит из за того что не удаляю этот объект.Ок,а я вот пробывал удалить таким образом: Как я думаю, это из-за того, что deleteLater удаляет объект при очередном входе в event loop. А так как нитка уже завершилась, то ее event loop уже остановлен.connect(this,SIGNAL(finished()),socket,SLOT(deleteLater())); почему этот вариант не катит? Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 00:28 :)ок,спасибо большое,будем разбираться,доброй ночи :)
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 08:57 Ок,терь я делаю так:
void socket_thread::run() { QTcpSocket socket; if (!socket.setSocketDescriptor(descriptor)) { emit signalSocketError(socket.peerAddress().toString(),"error"); return; } com=new socket_coming(&socket); ...... } А вот это ему терь не нравится: socket_coming::~socket_coming() { delete socket; } Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 08:58 Ок,терь я делаю так: Сокет создается на стеке, его больше не надо удалять delete, он сам разрушиться при выходе из run.void socket_thread::run() { QTcpSocket socket; if (!socket.setSocketDescriptor(descriptor)) { emit signalSocketError(socket.peerAddress().toString(),"error"); return; } ip_address=socket.peerAddress().toString(); com=new socket_coming(&socket); ...... } А вот это ему терь не нравится: socket_coming::~socket_coming() { delete socket; } Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 09:02 :) тогда прихожу к тому,что он мне пишет
QSocketNotifier: Multiple socket notifiers for same socket 1592 and type Read ну и память соотвестно на половину удаляется Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 09:05 Приведу на всякий случай конечный код.В главном потоке:
void main_widget::slotComingNewConnection() { coming_socket=serverComing->nextPendingConnection(); socket_thread *sock_thread=new socket_thread(coming_socket->socketDescriptor()); connect(sock_thread,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateComingTerminalsList(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearComingTerminalsList(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalComingReadyWrite(QString)),this,SLOT(slotCreateOutGoing(QString)),Qt::QueuedConnection); connect(this,SIGNAL(signalWriteComing(QString,QString)),sock_thread,SLOT(slotComingWrite(QString,QString))); connect(sock_thread,SIGNAL(signalCloseThread(QString)),this,SLOT(slotBeforeCloseSocket(QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalSocketError(QString,QString)),this,SLOT(slotComingSocketError(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalCloseThread()),sock_thread,SLOT(quit())); connect(sock_thread,SIGNAL(finished()),sock_thread,SLOT(deleteLater())); sock_thread->start(); } В потоке: void socket_thread::run() { QTcpSocket socket; if (!socket.setSocketDescriptor(descriptor)) { emit signalSocketError(socket.peerAddress().toString(),"error"); return; } com=new socket_coming(&socket); connect(com,SIGNAL(socketReadyWriteSignal(QString)),this,SLOT(slotComingReadyWrite(QString))); connect(this,SIGNAL(signalComingWrite(QString,QString)),com,SLOT(slotWrite(QString,QString))); connect(com,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateTerminals(QString,QString))); connect(com,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearTerminals(QString,QString))); connect(com,SIGNAL(signalError(QString,QString)),this,SLOT(slotSocketError(QString,QString))); connect(com,SIGNAL(socketDisconnected()),this,SLOT(closeThread())); exec(); } socket_thread::~socket_thread() { delete com; } В классе: socket_coming::socket_coming(QTcpSocket *soc):QObject(),socket(soc),val("") { connect(socket,SIGNAL(readyRead()),this,SLOT(slotReadyRead())); connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slotSocketError(QAbstractSocket::SocketError))); connect(socket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); } Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 09:09 Возможно, это из-за того, что объект com (класса socket_coming), который использует этот сокет еще не разрушен.
Можно попробовать создавать его также на стеке. Покажи как разрушаются объекты com. Код
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 09:16 :) :)точно,все терь 100% работает,большое спасибо BRE :)
Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 09:20 Несколько мыслей:
* По мне, так лучше чтобы объект socket был членом класса socket_coming и создавался соответственно в его конструкторе. * Между потоками можно передавать сами объекты QTcpSocket (вместо дескрипторов), главное сделать этому объекту moveToThread в поток которому он передается. Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 09:44 Согласен.Вот пытаюсь переделать по поводу первого замечания,вот код:
В главном: void main_widget::slotComingNewConnection() { coming_socket=serverComing->nextPendingConnection(); socket_thread *sock_thread=new socket_thread(coming_socket->socketDescriptor()); connect(sock_thread,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateComingTerminalsList(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearComingTerminalsList(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalComingReadyWrite(QString)),this,SLOT(slotCreateOutGoing(QString)),Qt::QueuedConnection); connect(this,SIGNAL(signalWriteComing(QString,QString)),sock_thread,SLOT(slotComingWrite(QString,QString))); connect(sock_thread,SIGNAL(signalCloseThread(QString)),this,SLOT(slotBeforeCloseSocket(QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalSocketError(QString,QString)),this,SLOT(slotComingSocketError(QString,QString)),Qt::QueuedConnection); connect(sock_thread,SIGNAL(signalCloseThread()),sock_thread,SLOT(quit())); connect(sock_thread,SIGNAL(finished()),sock_thread,SLOT(deleteLater())); sock_thread->start(); } В потоке: socket_thread::socket_thread(int descr):QThread() { descriptor=descr; } void socket_thread::run() { socket_coming com(descriptor); connect(&com,SIGNAL(socketReadyWriteSignal(QString)),this,SLOT(slotComingReadyWrite(QString))); connect(this,SIGNAL(signalComingWrite(QString,QString)),&com,SLOT(slotWrite(QString,QString))); connect(&com,SIGNAL(signalUpdateTerminals(QString,QString)),this,SLOT(slotUpdateTerminals(QString,QString))); connect(&com,SIGNAL(signalClearTerminals(QString,QString)),this,SLOT(slotClearTerminals(QString,QString))); connect(&com,SIGNAL(signalError(QString,QString)),this,SLOT(slotSocketError(QString,QString))); connect(&com,SIGNAL(socketDisconnected()),this,SLOT(closeThread())); exec(); } В классе: socket_coming::socket_coming(int descr):QObject(),descriptor(descr),val("") { socket=new QTcpSocket; socket->setSocketDescriptor(descriptor); connect(socket,SIGNAL(readyRead()),this,SLOT(slotReadyRead())); connect(socket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(slotSocketError(QAbstractSocket::SocketError))); connect(socket,SIGNAL(disconnected()),this,SLOT(slotDisconnected())); } socket_coming::~socket_coming() { delete socket; } Выводит опять ту ошибку: QSocketNotifier: Multiple socket notifiers for same socket 3644 and type Read Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 10:08 :)Возникла такая мысль,что это происходит потому,что сокет не удаляется,а он не удаляется потому что класс потока не удаляется сразу,там ведь deleteLater().А как решить иначе,не знаю.
Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 10:21 Попробуй так удалять:
Код
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 10:38 Сделал,все равно так же.Могу только добавить что память ведет себя интересно.При создании сокета в первый раз а потом его удалении удаляется ток половина памяти.Но в дальнейшем при создании память увеличивается уже не на 0.2 а на 0.3,а при удалении удаляется 0.2.
Да, и событие finished() точно происходит. Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 11:17 Сделал,все равно так же.Могу только добавить что память ведет себя интересно.При создании сокета в первый раз а потом его удалении удаляется ток половина памяти.Но в дальнейшем при создании память увеличивается уже не на 0.2 а на 0.3,а при удалении удаляется 0.2. Стоп. Ты передаешь дескриптор, значит объект QTcpSocket созданный в QTcpServer остается живым и будет удален при разрушении объекта QTcpServer.Да, и событие finished() точно происходит. Вот этот объект coming_socket будет жить до тех пор пока будет жить объект serverComing. Код
Попробуй сделать второй вариант, т.е. передавать в поток сам объект QTcpSocket и удалять его при завершении потока. Код
Название: Re: Проблема с удалением сокета Отправлено: xaleva от Октябрь 30, 2009, 11:26 :)Да,работает,память не растет.Кстати,я не стал говорить,но в прошлый раз оказалось все таки,что она росла :D.Вощем все понятно,почему.По правде говоря я и сам мысленно понимал что объект то не удаляется,т.к я просто переношу дескриптор.Просто не понятно тогда зачем во всех книгах и во всех приложениях тестовых советуют именно через дескриптор делать,они ведь тоже переносят в отдельный поток.У них этих проблем не возникает чтоли? :)
Название: Re: Проблема с удалением сокета Отправлено: BRE от Октябрь 30, 2009, 11:31 У них этих проблем не возникает чтоли? :) Нет, у писателей вообще проблем не много. ;)Название: Re: Проблема с удалением сокета Отправлено: Ruzzz от Ноябрь 02, 2009, 20:43 Просто не понятно тогда зачем во всех книгах и во всех приложениях тестовых советуют именно через дескриптор делать,они ведь тоже переносят в отдельный поток.У них этих проблем не возникает чтоли? :) Через дескриптор, потому что там переопределяют incomingConnection а не ловят сигнал newConnection. Именно в QTcpServer::incomingConnection и создается объект QTcpSocket который у вас давал утечку, точнее он не удалялся пока не разрушиться QTcpServer. Посмотрите пример Threaded Fortune Server. |