我为接受来自不同客户端的连接的服务器编写了代码。每个客户端都在不同的线程中服务。每个线程访问数据库以获取数据,然后将此数据更新到连接到服务器的所有客户端。
1)当用户界面第一次向服务器请求数据时,它会正确响应,但在那之后服务器没有读取套接字,即服务器的 readyread() 没有被调用。有趣的是,这在mac 和 linux中运行良好,此问题仅在windows上可见
2)我能够验证当 DB 模块发出一个被线程捕获的信号时,会发生挂起,因为当我移除发射时一切正常。
在这里,我附上了所有需要的 .h 和 .cpp 代码
定义文件
#ifndef DEFN_H
#define DEFN_H
struct PresetData{
QString ID;
QString name;
QString value;
QString source;
};
#endif // DEFN_H
主文件
#include <QCoreApplication>
#include "myserver.h"
#include "mydb.h"
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
MyDB db;
MyServer server(&db);
server.startServer();
return a.exec();
}
数据库文件
#ifndef MYDB_H
#define MYDB_H
#include <QObject>
#include <QtSql>
#include "Defn.h"
class MyDB : public QObject
{
Q_OBJECT
public:
explicit MyDB(QObject *parent = 0);
signals:
void dataAvailable(QString ID, QString name, QString value, QString source);
public slots:
void onUpdateData(QString ID, QString name, QString value, QString source);
void onGetData(QString ID, QString name, QString value, QString source);
private:
QSqlDatabase m_db;
};
#endif // MYDB_H
我的数据库
#include "mydb.h"
MyDB::MyDB(QObject *parent) :
QObject(parent)
{
m_db = QSqlDatabase::addDatabase("QSQLITE");
m_db.setConnectOptions();
m_db.setDatabaseName("D:/MySimulator/New Folder/TCPServer1/DB.db");
if (m_db.open()){
qDebug() << "DB opened succesfully" ;
}else{
qDebug() << "DB Opening failed" ;
}
QStringList tables = m_db.tables();
if (tables.contains("Presets", Qt::CaseInsensitive)){
qDebug() << "DB Contains Data" ;
return;
}
}
void MyDB::onGetData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onGetData" ;
QString queryString = "SELECT Value from 'Presets' where ID = \'" + ID + "\'";
QSqlQuery q;
bool result = q.exec(queryString);
if (result){
if (q.next()){
value = q.value(q.record().indexOf("Value")).toString();
qDebug() << " Retrieved Value = " << value ;
emit dataAvailable(ID, name, value, source);
}else{
qDebug("Empty Result");
}
}else{
qDebug("NO Result");
}
}
void MyDB::onUpdateData(QString ID, QString name, QString value, QString source)
{
qDebug() << "onUpdateData" ;
QString queryString = "UPDATE 'Presets' SET Value = \'" + value + "'\ WHERE ID = \'" + ID + "\'";
QSqlQuery q;
QSqlDatabase::database().transaction();
bool result = q.exec(queryString);
if (result){
QSqlDatabase::database().commit();
onGetData(ID, name, "", "000");
}else{
qDebug("NO Result");
}
}
我的线程.h
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QAbstractSocket>
#include <QDebug>
#include "Defn.h"
#include "mydb.h"
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(int ID, MyDB* db, QObject * parent = 0);
void run();
void parseInput(QString string);
signals:
void error(QTcpSocket::SocketError socketError);
void updateData(QString ID, QString name, QString value, QString source);
void getData(QString ID, QString name, QString value, QString source);
public slots:
void readyRead();
void disconnected();
void onDataAvailable(QString ID, QString name, QString value, QString source);
private:
QTcpSocket* socket;
int socketDescriptor;
MyDB* db;
};
#endif // MYTHREAD_H
我的线程.cpp
#include "mythread.h"
#include "qtcpserver.h"
#include "qabstractsocket.h"
MyThread::MyThread(int ID, MyDB* db, QObject * parent ):
QThread(parent)
{
this->socketDescriptor = ID ;
this->db = db;
}
void MyThread::run()
{
// thread starts here.
qDebug() << socketDescriptor << "Starting Thread" ;
socket = new QTcpSocket();
if (!socket->setSocketDescriptor(this->socketDescriptor)){
emit error(socket->error());
return;
}
connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead()), Qt::DirectConnection);
connect(socket, SIGNAL(disconnected()), this, SLOT(disconnected()), Qt::DirectConnection);
connect(this, SIGNAL(getData(QString, QString , QString , QString )), this->db, SLOT(onGetData(QString , QString , QString , QString )));
connect(this, SIGNAL(updateData(QString , QString , QString , QString )), this->db, SLOT(onUpdateData(QString , QString , QString , QString )));
connect(this->db, SIGNAL(dataAvailable(QString , QString , QString , QString )), this, SLOT(onDataAvailable(QString , QString , QString , QString )));
qDebug() << socketDescriptor << "Client Connected" ;
exec();
}
void MyThread::readyRead()
{
QByteArray data = socket->readAll();
qDebug() << socketDescriptor << "Data in: " << data;
parseInput(data);
}
void MyThread::disconnected()
{
qDebug() << socketDescriptor << "Disconnected" ;
socket->deleteLater();
exit(0);
}
void MyThread::parseInput(QString dataFromTCP)
{
qDebug() << socketDescriptor << ":" <<"parseInput " << dataFromTCP;
if (dataFromTCP.isEmpty())
return;
QStringList list1 = dataFromTCP.split("\n", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list1 BEGIN";
for (int i = 0 ; i < list1.count(); i++)
{
qDebug() << i<< ":" << list1.at(i);
}
qDebug() << socketDescriptor << ":" << "list1 END";
if (list1.count() < 1){
return;
}
QString strMessage = "";
for (int i = 0 ; i < list1.count() ; i++)
{
strMessage = list1[i];
QStringList list2 = strMessage.split(" ", QString::SkipEmptyParts);
qDebug() << socketDescriptor << ":" << "list2 BEGIN";
for (int i = 0 ; i < list2.count(); i++)
{
qDebug() << i<< ":" << list2.at(i);
}
qDebug() << socketDescriptor << ":" << "list2 END";
if (list2.count() < 1){
break;
}
QString ID = list2[1];
QString source = QString::number(socketDescriptor) ;
if (list2[0] == "GET"){
emit getData(ID, "", "", source);
}
else if (list2[0] == "UPD"){
QString value = list2[2];
emit updateData(ID, "", value, source);
}
}
}
void MyThread::onDataAvailable(QString ID, QString name, QString value, QString source)
{
if( (QString::number(socketDescriptor) == source) || ("000" == source ) ) {
qDebug() << socketDescriptor << " : On Data Available " << ID << name << value ;
QString data = "DATA " + ID + " " + value + " " + "\n" ;
QByteArray ba;
ba.append(data);
socket->write(ba);
}
}
我的服务器.h
#ifndef MYSERVER_H
#define MYSERVER_H
#include <QDebug>
#include <QObject>
#include <QTCPServer>
#include <QTCPSocket>
#include "mythread.h"
#include "mydb.h"
class MyServer: public QTcpServer
{
Q_OBJECT
public:
explicit MyServer(MyDB* pdb, QObject* parent = 0);
void startServer();
signals:
public slots:
protected:
void incomingConnection(qintptr socketDescriptor);
private:
MyDB* pdb ;
};
#endif // MYSERVER_H
我的服务器.cpp
#include "myserver.h"
MyServer::MyServer(MyDB* pdb, QObject* parent ):
QTcpServer(parent)
{
this->pdb = pdb;
}
void MyServer::startServer()
{
if (!this->listen(QHostAddress::Any, 1234)){
qDebug() << "Could not Start Server " << this->errorString();
}
else{
qDebug() << " Server Running... ";
}
}
void MyServer::incomingConnection(qintptr socketDescriptor)
{
qDebug() << socketDescriptor << " Connecting... ";
MyThread *thread = new MyThread(socketDescriptor, pdb, this);
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
这里我上面提到的信号是来自“mydb.cpp”的dataAvailable。如果我注释掉该行,则服务器会响应客户端消息。但是,如果在初始响应之后发出该信号,则服务器似乎挂起并且不再对来自客户端的传入消息做出反应。相同的代码在 mac 和 linux 中运行良好。但它仅在 Windows 中存在此问题。有人可以让我知道我做错了什么,它只在 Windows 中失败了吗?提前感谢您帮助我。
编辑:
这段代码的目的是,每当一个线程导致对数据库的更新调用时,每个线程(包括调用更新的线程)都会收到有关更改的通知。因此,预计当时运行的其他线程也会收到信号。
这是对服务器的期望:
能够同时允许来自多个客户端的 TCP 连接。
如果任何客户端请求信息,它会通过 TCP 连接获取所需的数据。
如果任何客户端更新信息,包括更新客户端在内的所有客户端都会通过 TCP 连接获得通知。