Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > С/С++: Кроссплатформенное программирование, Qt/Gtk+/wxWidgets > Передача дескриптора в поток, без сигналов


Автор: null56 30.6.2009, 19:18
Задача:
В основном потоке висит слушающий сокет (QSslSocket) и ожидает соединений. В дочернем работает обработчик событий, который проверяет свою очередь на поступление новых дескрипторов сокетов.
При поступлении нового сокета, основной поток засовывает дескриптор (число int) в очередь дочернего потока и продолжает слушать, дочерний поток периодами просматривает очередь и вытаскивает оттуда дескриптор сокета, затем создает объект QSslSocket и работает непосредственно с ним.... очередь реализована в виде нитебезопасного QList<int>

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

class TcpServer : public QTcpServer
{
public:
    TcpServer();
     void incomingConnection ( int socketDescriptor );
private:
    Thread m_SocketThread;
};


Код

TcpServer::TcpServer()
{
    m_SocketThread.start();
}

void
TcpServer :: incomingConnection ( int socketDescriptor )
{
    qDebug("New socket: %d", socketDescriptor);
    m_SocketThread.add(socketDescriptor);
}


Дочерний поток
Код

class Thread : public QThread
{
public:
    Thread();
    void add(int sd);
    void checkNewConnection();

protected:
    void run();
    
private:
    QMutex m_Mutex;
    volatile bool m_Stop;
    QList<int> m_NewConnectionList;
};


Код

Thread::Thread() :
    m_Stop(false)
{
}


void
Thread :: run()
{
    while (!m_Stop)
    {
        checkNewConnection();
        msleep(300);
    }
}

void
Thread :: add(int socketDescriptor)
{
    QMutexLocker lock(&m_Mutex);
    m_NewConnectionList.push_back(socketDescriptor);
}


void
Thread :: checkNewConnection()
{
    QMutexLocker lock(&m_Mutex);
    while (!m_NewConnectionList.isEmpty())
    {
        int socket_descriptor = m_NewConnectionList.takeFirst();
        QSslSocket * sock = new QSslSocket;
        if (!sock->setSocketDescriptor(socket_descriptor)) // связь потеряна, соединения нет или что - то не так
            { qDebug("Fail"); }
        // далее сертификат и ключ и startServerEncryption
    }
}



Если кто знает в чем проблема, пожалуйста объясните...
Заранее благодарен за помощь

Автор: SABROG 30.6.2009, 19:40
И в консоль никаких варнингов не сыпется?

Автор: null56 1.7.2009, 14:06
В общем ситуация в следующем....
1) Сам сокет рабочий остается и  коннект есть, это можно посмотреть, если использовать не ssl соединение
2) Ssl соединение происходит правильно, фукнции установки связи, загрузки сертификата и ключа просходят одинакого, как в родительском, так и в дочернем потоке
Итог: что - то не так с ssl соединением, почему оно не хочет устанавливаться в таких, казалось бы логичных условиях, остается загадкой, надеюсь, что ответ мне дадут на багзилле
Я прикрепил простенький примерчик, того, чего пытаюсь сделать, у кого будет время соберите, гляньте, может я не прав где - то

Автор: SABROG 1.7.2009, 14:28
Цитата(null56 @  1.7.2009,  14:06 Найти цитируемый пост)
соберите, гляньте


Чет не собирается

Код

g++ -c -O2 -frtti -fexceptions -mthreads -Wall -DUNICODE -DQT_LARGEFILE_SUPPORT
-DQT_DLL -DQT_NO_DEBUG -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"..\
..\qt-win-opensource-src-4.5.0\include\QtCore" -I"..\..\qt-win-opensource-src-4.
5.0\include\QtNetwork" -I"..\..\qt-win-opensource-src-4.5.0\include" -I"..\..\qt
-win-opensource-src-4.5.0\include\ActiveQt" -I"release" -I"." -I"..\..\qt-win-op
ensource-src-4.5.0\mkspecs\win32-g++" -o release\main.o main.cpp
In file included from main.cpp:2:
tcpsocket.h:8: error: expected class-name before '{' token
tcpsocket.h:15: error: `QAbstractSocket' has not been declared
tcpsocket.h:15: error: `SocketState' has not been declared
tcpsocket.h:15: error: ISO C++ forbids declaration of `socketState' with no type

tcpsocket.h:16: error: `QSslSocket' has not been declared
tcpsocket.h:16: error: `SslMode' has not been declared
tcpsocket.h:16: error: ISO C++ forbids declaration of `mode' with no type
tcpsocket.h:17: error: `QSslError' was not declared in this scope
tcpsocket.h:17: error: template argument 1 is invalid
tcpsocket.h:17: error: ISO C++ forbids declaration of `errors' with no type
tcpsocket.h:19: error: `QAbstractSocket' has not been declared
tcpsocket.h:19: error: `SocketError' has not been declared
tcpsocket.h:19: error: ISO C++ forbids declaration of `err' with no type
main.cpp: In function `int main(int, char**)':
main.cpp:9: error: 'class SslSocket' has no member named 'connectToHostEncrypted
'
mingw32-make[1]: *** [release/main.o] Error 1
mingw32-make[1]: Leaving directory `C:/SABROG/sslSocket/socket_client'
mingw32-make: *** [release] Error 2

C:\SABROG\sslSocket\socket_client>cd ..

C:\SABROG\sslSocket>cd ThreadServer

C:\SABROG\sslSocket\ThreadServer>qmake

C:\SABROG\sslSocket\ThreadServer>mingw32-make release
mingw32-make -f Makefile.Release
mingw32-make[1]: Entering directory `C:/SABROG/sslSocket/ThreadServer'
g++ -c -O2 -frtti -fexceptions -mthreads -Wall -DUNICODE -DQT_LARGEFILE_SUPPORT
-DQT_DLL -DQT_NO_DEBUG -DQT_NETWORK_LIB -DQT_CORE_LIB -DQT_THREAD_SUPPORT -I"..\
..\qt-win-opensource-src-4.5.0\include\QtCore" -I"..\..\qt-win-opensource-src-4.
5.0\include\QtNetwork" -I"..\..\qt-win-opensource-src-4.5.0\include" -I"..\..\qt
-win-opensource-src-4.5.0\include\ActiveQt" -I"release" -I"." -I"..\..\qt-win-op
ensource-src-4.5.0\mkspecs\win32-g++" -o release\main.o main.cpp
In file included from tcpserver.h:5,
                 from main.cpp:2:
thread.h:22: error: ISO C++ forbids declaration of `QSslSocket' with no type
thread.h:22: error: expected `;' before '*' token
In file included from main.cpp:2:
tcpserver.h:15: error: ISO C++ forbids declaration of `QSslSocket' with no type
tcpserver.h:15: error: expected `;' before '*' token
mingw32-make[1]: *** [release/main.o] Error 1
mingw32-make[1]: Leaving directory `C:/SABROG/sslSocket/ThreadServer'
mingw32-make: *** [release] Error 2

---
Похоже у меня Qt собрана с поддержкой OpenSSL... Проверить не могу, сорри..

Автор: null56 2.7.2009, 09:33
Блин... тут поэкспериментировали с одним знакомым и он нашел способ при котором работать стало, но я не понимаю, это не совсем логично
Работать стало, если я вызываю одну из функций 
Код

//m_Sock->waitForBytesWritten(1) ;
//m_Sock->waitForReadyRead(1);

после вызова startServerEncryption(), даже на одну миллисекунду и всё отрабатывает
В чем проблема? ведь с функцией waitForEncrypted ничего не работает, а с ними работает

Автор: null56 3.7.2009, 10:03
Собственно я догадался в чем проблема и, к сожалению, решить ее нельзя...
QSslSocket дальний родственник QObject и все события, которые происходят с самим сокетом, могут определяться только в EventLoop.
То есть, когда создается новое соединение и я передаю его в тот поток в котором НЕ работает обработчик событий, то объект класса QSslSocket становится мертвым по отношению к событиям, связанным с находящимся внутри объекта сокетом...
Сейчас ставил экспиременты с  обычным незащищенным соединением, и  пытался серверу передать данные от клиента... серверныый сокет молчал на вызовы функций
Код

bytesAvailable();
read();

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

Автор: SABROG 3.7.2009, 16:08
Ничего не понимаю, собрал Qt из репозитория, а прога все-равно не находит QSslSocket.  smile 

Автор: null56 3.7.2009, 17:09
попробуй выкачай qt-creator, целиковый под выньду, у меня работал.... у меня нет винды и я никогда не собирал и не ставил qt под винду
я работаю на gentoo, всё компилируя.... проблем вроде не было
Код

emerge -pv qt-core

These are the packages that would be merged, in order:

Calculating dependencies... done!
[ebuild   R   ] x11-libs/qt-core-4.5.2  USE="glib iconv qt3support ssl -debug -doc -pch" 0 kB

флаг выставлен... остальное сам тянет

Автор: SABROG 6.7.2009, 11:46
Собрал таки. Вот такое вижу в консоли:

//ssl_client
Код

onStateChanged: 1
onStateChanged: 2
onStateChanged: 3
onModeChanged 1
onSSlErrors: 1
"The certificate is self-signed, and untrusted"
ENCRYPTED
ON ready read
Data: PREVED CLIENT


//threadServer
Код

New socket: 1760
Valid certificate

Автор: null56 6.7.2009, 20:44
SABROG, в каком случае ты это видишь? когда передается в дочерний поток?

Автор: SABROG 6.7.2009, 21:01
Цитата(null56 @ 6.7.2009,  20:44)
SABROG, в каком случае ты это видишь? когда передается в дочерний поток?

На самом деле я просто тупо скомпилил сервер и клиент и запустил оба.

Автор: null56 7.7.2009, 11:55
SABROG, если не сложно... в файле tcpserver.cpp в функции TcpServer :: incomingConnection ( int socketDescriptor ), закомментируй вызов create, а m_SocketThread.add раскомментируй и проверь, будет ли тот же результат... буду благодарен
вот чего тролли написали
Цитата

After you get the incoming QTcpSocket, can you call moveToThread for it and then pass it to the other thread and there in the other thread create a QSslSocket out of it?

бред какой - то... тоже не катит без евентлупа

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)