天天看點

QT分析之網絡程式設計(四)

前面分析中,一個問題一直沒有解決:新生成的SOCKET是什麼時候加入WSASelect()的?另外還有一個不是很大的問題,close流程。

在QEventDispatcherWin32Private::doWsaAsyncSelect()中WSAAsyncSelect()設定一個斷點,觀察call stack:

>    QtCored4.dll!QEventDispatcherWin32Private::doWsaAsyncSelect(int socket=0x00001628)  行633    C++

     QtCored4.dll!QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier * notifier=0x00c6f248)  行829    C++

     QtCored4.dll!QSocketNotifier::QSocketNotifier(int socket=0x00001628, QSocketNotifier::Type type=Write, QObject * parent=0x00c66228)  行185    C++

     QtNetworkd4.dll!QWriteNotifier::QWriteNotifier(int fd=0x00001628, QNativeSocketEngine * parent=0x00c66228)  行1053 + 0x1a 位元組    C++

     QtNetworkd4.dll!QNativeSocketEngine::setWriteNotificationEnabled(bool enable=true)  行1118 + 0x2d 位元組    C++

     QtNetworkd4.dll!QAbstractSocketPrivate::_q_connectToNextAddress()  行996    C++

     QtNetworkd4.dll!QAbstractSocketPrivate::_q_startConnecting(const QHostInfo & hostInfo={...})  行890    C++

     QtNetworkd4.dll!QAbstractSocket::qt_metacall(QMetaObject::Call _c=InvokeMetaMethod, int _id=0x0000000a, void * * _a=0x00c6e510)  行104 + 0x16 位元組    C++

     QtNetworkd4.dll!QTcpSocket::qt_metacall(QMetaObject::Call _c=InvokeMetaMethod, int _id=0x00000012, void * * _a=0x00c6e510)  行58 + 0x14 位元組    C++

     QtCored4.dll!QMetaCallEvent::placeMetaCall(QObject * object=0x00c4f790)  行478    C++

     QtCored4.dll!QObject::event(QEvent * e=0x00c4d8a0)  行1102 + 0x14 位元組    C++

     QtGuid4.dll!QApplicationPrivate::notify_helper(QObject * receiver=0x00c4f790, QEvent * e=0x00c4d8a0)  行4065 + 0x11 位元組    C++

     QtGuid4.dll!QApplication::notify(QObject * receiver=0x00c4f790, QEvent * e=0x00c4d8a0)  行3605 + 0x10 位元組    C++

     QtCored4.dll!QCoreApplication::notifyInternal(QObject * receiver=0x00c4f790, QEvent * event=0x00c4d8a0)  行610 + 0x15 位元組    C++

     QtCored4.dll!QCoreApplication::sendEvent(QObject * receiver=0x00c4f790, QEvent * event=0x00c4d8a0)  行213 + 0x39 位元組    C++

     QtCored4.dll!QCoreApplicationPrivate::sendPostedEvents(QObject * receiver=0x00000000, int event_type=0x00000000, QThreadData * data=0x00bc8890)  行1247 + 0xd 位元組    C++

     QtCored4.dll!QEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...})  行679 + 0x10 位元組    C++

     QtGuid4.dll!QGuiEventDispatcherWin32::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...})  行1182 + 0x15 位元組    C++

     QtCored4.dll!QEventLoop::processEvents(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...})  行150    C++

     QtCored4.dll!QEventLoop::exec(QFlags<enum QEventLoop::ProcessEventsFlag> flags={...})  行201 + 0x2d 位元組    C++

     QtGuid4.dll!QDialog::exec()  行499    C++

     fortuneclient.exe!main(int argc=0x00000001, char * * argv=0x00bc8750)  行51 + 0x9 位元組    C++

     fortuneclient.exe!WinMain(HINSTANCE__ * instance=0x00400000, HINSTANCE__ * prevInstance=0x00000000, char * __formal=0x001520e2, int cmdShow=0x00000001)  行137 + 0x12 位元組    C++

     fortuneclient.exe!__tmainCRTStartup()  行574 + 0x35 位元組    C

     fortuneclient.exe!WinMainCRTStartup()  行399    C

     kernel32.dll!7c82f23b()    

     [下面的架構可能不正确和/或缺失,沒有為 kernel32.dll 加載符号]   

看QNativeSocketEngine::setWriteNotificationEnabled()的代碼實作:

void QNativeSocketEngine::setWriteNotificationEnabled(bool enable)

{

    Q_D(QNativeSocketEngine);

    if (d->writeNotifier) {

        d->writeNotifier->setEnabled(enable);

    } else if (enable && d->threadData->eventDispatcher) {

        d->writeNotifier = new QWriteNotifier(d->socketDescriptor, this);

        d->writeNotifier->setEnabled(true);

    }

}

在QWriteNotifier對象建立的時候,引起其父類的建構:QSocketNotifier

QSocketNotifier::QSocketNotifier(int socket, Type type, QObject *parent)

    : QObject(parent)

    if (socket < 0)

        qWarning("QSocketNotifier: Invalid socket specified");

    sockfd = socket;

    sntype = type;

    snenabled = true;

    Q_D(QObject);

    if (!d->threadData->eventDispatcher) {

        qWarning("QSocketNotifier: Can only be used with threads started with QThread");

    } else {

        d->threadData->eventDispatcher->registerSocketNotifier(this);

原來是通過擷取目前線程資料得到Dispatcher的指針(QEventDispatcherWin32),通過其注冊QNativeSocketEngine對象自己本身。

void QEventDispatcherWin32::registerSocketNotifier(QSocketNotifier *notifier)

    Q_ASSERT(notifier);

    int sockfd = notifier->socket();

    int type = notifier->type();

    Q_D(QEventDispatcherWin32);

    QSNDict *sn_vec[3] = { &d->sn_read, &d->sn_write, &d->sn_except };

    QSNDict *dict = sn_vec[type];

    if (QCoreApplication::closingDown()) // ### d->exitloop?

        return; // after sn_cleanup, don't reinitialize.

    if (dict->contains(sockfd)) {

        const char *t[] = { "Read", "Write", "Exception" };

    /* Variable "socket" below is a function pointer. */

        qWarning("QSocketNotifier: Multiple socket notifiers for "

                 "same socket %d and type %s", sockfd, t[type]);

    QSockNot *sn = new QSockNot;

    sn->obj = notifier;

    sn->fd  = sockfd;

    dict->insert(sn->fd, sn);

    if (d->internalHwnd)

        d->doWsaAsyncSelect(sockfd);

在這裡跟前面分析的QEventDispatcherWin32消息處理搭上關系了,把QWriteNotifier對象加入到系統的清單中;在QApplication::exec()的消息循環中,就能夠擷取目标對象了。

繼續閱讀