Как начинающий Qt'шник решил разобраться с
QTcpSocket и привести в порядок мысли. Первым делом изучил класс QTcpSocket в Help'е. Затем изучил примеры
Fortune Server и
Threaded Fortune Server. Ну и решил сделать некий график для себя. Делюсь -
скачать файл для XMind или в виде картинки:
Немного комментариев и за одно вопросов.Работая с QTcpServer у нас есть две возможности обрабатывать входящие соединения:
- Переопределить incomingConnection
- Или ловить сигнал newConnection
После выполнения
listen, как я понимаю где-то в недрах QtNetwork выполняется QTcpServer::
waitForNewConnection, из которой идет вызов QTcpServerPrivate::
readNotification, в теле этой функции я и нашел такие вызовы:
QTcpServer::incomingConnection(int socketDescriptor);
emit newConnection();
То есть здесь и происходит вызов incomingConnection, а затем посылка сигнала newConnection. Что говорит нам, что эти способы не взаимоисключающие, и мы можем использовать их оба для своих нужд, мало ли.
Теперь хотел бы рассмотреть код QTcpServer::
incomingConnection(int socketDescriptor):
QTcpSocket *socket = new QTcpSocket(this);
socket->setSocketDescriptor(socketDescriptor);
d_func()->pendingConnections.append(socket);
Динамически в куче создается новый экземпляр сокета, связывается с входящим подключением и сохраняется в списке. Важно что QTcpSocket создается в основном потоке! Поэтому если мы не переопределяем
incomingConnection и хотим использовать сокет не в главном потоке, то не забываем делать: setParent(0) и потом QObject->moveToThread() и не забываем что теперь за удаление отвечаем мы. Интересно что добавляемый в список (в третьей строке) сокет, удаляется оттуда QTcpSocket *QTcpServer::
nextPendingConnection().
Теперь рассмотрим способ с сигналом
newConnection.
Создаем наследник QTcpServer, например myTcpServer. В его конструкторе связываем сигнал с нашим слотом строкой connect(myTcpServer, SIGNAL(newConnection()), myTcpServer, SLOT(connectionProcess()));. Далее в слоте имеет примерно такой код:
QTcpSocket *clientConnection = myTcpServer->nextPendingConnection();
connect(clientConnection, SIGNAL(disconnected()), clientConnection, SLOT(deleteLater()));
clientConnection->read(…);
clientConnection->write(…);
clientConnection->disconnectFromHost();
Первая строка извлекает раннее сохраненный в списке объект QTcpSocket. Важно, что он сохранялся в
incomingConnection, поэтому если мы ее будем переопределять, то использовать nextPendingConnection нельзя. Далее вторая строка, говорит что при дисконнекте мы поставим объект сокета в очередь на удаление. Если мы создали сокет динамически где-то раньше, то после того как сокет соединился, это верный способ для его удаления. В конце мы даем команду оборвать соединение.
Далее способ с переопределением
incomingConnectionВ примере
Threaded Fortune Server в теле функции создается новый поток, и уже в нем идет работа с сокетом, отвечающим за соединение. Но как я понимаю никто не мешает нам выполнять обработку прям здесь
. Но тут вопрос, будут ли проблемы с большим кол-вом соединений? Ведь мы не сохраняем их в список(очередь). Хотя по моему создание отдельных потоков, на одно процессорной машине не то что не увеличит скорость, но наоборот — уменьшить ее. Далее. Здесь используется setSocketDescriptor, который связывает объект сокета с дескриптором который получен ранее от системы. Ну а далее все как обычно. Еще стоит обратить внимание на waitForDisconnected, она заставляет нас не выходить быстро из функции, иначе будет удален tcpSocket, потому что мы объявили его не динамически. А если он будет удален, вполне возможно сокет не сможет корректно «отработать». Также если вы работаете с сокетом в отдельном потоке, waitForDisconnected заставляет не выходить из рабочей функции потока, и тем самым поток не «умирает», а он нужен, так как сокет использует его очередь сообщений, без которой он не сможет корректно разъединиться.
Везде в QTcpSocket используется асинхронный режим (без потока), кроме waitForNewConnection.
Мастера, прошу указать на ошибки!
UPD Спасибо BRE!
UPD http://www.xmind.net/share/ruzzzua/work-with-qtcpsocket/ — может кому пригодится