Название: QTcpServer при высокой нагрузке
Отправлено: RankoR от Ноябрь 29, 2010, 22:32
Приветствую! Пишу приложение, суть которого заключается в следующем: Клиент коннектится к моему серверу, сервер создает новый сокет, который коннектит к другому серверу, и перекидывает данные от клиента к другому серверу (и обратно). В общем-то похоже на проброс портов или прокси. Клиентские (полученные из QTcpServer) и серверные сокеты присоединены к одним и тем же сигналам onReadyRead и onDisconnected.
Проблема заключается вот в чем. При 10-50-70 одновременных подключениях к серверу все ок. Однако при сотне начинаются проблемы - клиент коннектится, но сигналы readyRead и disconnected перестают работать, в итоге я получаю кучу сокетов, висящих мертвым грузом, и сервер, не делающий ничего, но отличненько жрущий память. В чем может быть проблема? Неужели QTcpServer не выдерживает такой (не такой уж и большой) нагрузки?
Название: Re: QTcpServer при высокой нагрузке
Отправлено: voral от Ноябрь 30, 2010, 09:51
Вы по потокам разделяете? с "другим" сервером одно общее соединение или 1:1?
Название: Re: QTcpServer при высокой нагрузке
Отправлено: RankoR от Ноябрь 30, 2010, 15:41
void QListener::onConnection() { /* Getting the pending connection */ QTcpSocket *clientSocket = serverSocket.nextPendingConnection();
if ( ! clientSocket ) return;
QString ip = clientSocket->peerAddress().toString();
/* Checking if connection is allowed */
bool isInCache = false; QUserInfo userInfo;
userInfo = userInfoMap.value(ip, userInfo);
if ( ! userInfo.user.isEmpty() ) { if ( userInfo.lastUpdate.secsTo(QTime::currentTime()) < (60 * 10) ) isInCache = true; }
bool isAllowed = true;
/* If user is not in cache - get it from SQL and add to cache */ if ( ! isInCache ) { userInfo.user.clear();
if ( ! db.open() ) qDebug() << "Failed to open DB!";
QSqlQuery *sqlQuery = NULL; try { sqlQuery = new QSqlQuery(db); } catch(...) { qDebug() << "Exception! [1]"; return; }
if ( ! sqlQuery->exec(QString("SELECT user, threads FROM users WHERE ip='%1'").arg(ip)) ) { qDebug() << "Query failed:" << sqlQuery->lastError().text(); isAllowed = false; }
if ( sqlQuery->next() && isAllowed ) { userInfo.user = sqlQuery->value(0).toString(); userInfo.maxThreads = sqlQuery->value(1).toInt(); userInfo.lastUpdate = QTime::currentTime();
userInfoMap.remove(ip); // Remove the old user info from the cache userInfoMap.insert(ip, userInfo); // Insert user info to the cache } else isAllowed = false;
sqlQuery->finish(); delete sqlQuery; db.close();
if ( isAllowed ) qDebug() << "Cache record for" << ip << "is deprecated and was updated"; }
/* Check if threads limit is reached */ qint32 connectionsCount = connectionsList.count(ip);
if ( connectionsCount >= userInfo.maxThreads ) { connectionsList.removeAt(connectionsList.indexOf(ip)); }
/* If not allowed - disconnect */ if ( ! isAllowed ) { clientSocket->disconnectFromHost(); clientSocket->deleteLater(); return; }
/* Trying to connect to the proxy */ QTcpSocket *proxySocket = NULL; try { proxySocket = new QTcpSocket; } catch(...) { qDebug() << "Exception (2)!"; clientSocket->disconnectFromHost(); clientSocket->deleteLater(); return; }
if ( ! proxySocket ) { clientSocket->disconnectFromHost(); clientSocket->deleteLater(); return; }
/* Get the proxy host & port from the DB */
if ( proxiesCount == 0 ) { qDebug() << "Proxies count == 0!"; clientSocket->disconnectFromHost(); clientSocket->deleteLater(); return; }
mutex.lock(); QString host = proxiesList.at(currentProxy); quint16 port = portsList.at(currentProxy);
if ( currentProxy >= (proxiesCount - 1) ) currentProxy = 0; else currentProxy++; mutex.unlock();
/* Connect to the proxy */
proxySocket->connectToHost(host, port);
if ( ! proxySocket->waitForConnected(5000) ) { qDebug() << "Failed to connect to the proxy!"; clientSocket->disconnectFromHost(); clientSocket->deleteLater(); return; }
connectionsCount++; connectionsList.append(ip); qDebug() << "New connection accepted! " << connectionsCount << "connections for this IP"; qDebug() << "Total:" << socketsMap.count() << "connections";
/* Add sockets to the map and connect to the slots */ clientSocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1); proxySocket->setSocketOption(QAbstractSocket::KeepAliveOption, 1);
socketsMap[clientSocket] = proxySocket;
connect(clientSocket, SIGNAL(readyRead()), this, SLOT(onReadyRead())); connect(proxySocket, SIGNAL(readyRead()), this, SLOT(onReadyRead()));
connect(clientSocket, SIGNAL(disconnected()), this, SLOT(onDisconnected())); connect(proxySocket, SIGNAL(disconnected()), this, SLOT(onDisconnected())); }
Вот код, немного индусский, ибо писался в спешке. Функция выполняется до конца.
|