前面分析中,一個問題一直沒有解決:新生成的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()的消息循環中,就能夠擷取目标對象了。