天天看点

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()的消息循环中,就能够获取目标对象了。

继续阅读