热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

cqt类内的服务器线程(需要互斥锁吗?)

我创建了这个服务器类,该服务器类在出现新的连接时启动线程.在某些情况下,它可以正常工作,但不是很稳定.我正在尝试解决问题.我的调试器告诉我有关qmutex的信息.如果有人可以发现问

我创建了这个服务器类,该服务器类在出现新的连接时启动线程.在某些情况下,它可以正常工作,但不是很稳定.我正在尝试解决问题.我的调试器告诉我有关qmutex的信息.如果有人可以发现问题. TY

它通过信号和时隙与父节点连接,并且还取回数据.

这是标题:

#ifndef FORTUNESERVER_H
#define FORTUNESERVER_H
#include
#include
#include
#include
#include
using namespace std;
class FortuneServer : public QTcpServer
{
Q_OBJECT
public:
FortuneServer(QObject *parent = 0);
public slots:
void procesServerString(string serverString);
void getStringToThread(string serverString);
protected:
void incomingConnection(int socketDescriptor);
private:
QStringList fortunes;
signals:
void procesServerStringToParent(string serverString);
void getStringToThreadSignal(string serverString);
};
class FortuneThread : public QObject
{
Q_OBJECT
public:
FortuneThread(int socketDescriptor, QObject *parent);
public slots:
void getString();
void sendString(string sendoutString);
signals:
void error(QTcpSocket::SocketError socketError);
void fromThreadString(string serverString);
void finished();
private:
int socketDescriptor;
QString text;
QTcpSocket tcpSocket;
};
#endif

和抄送:

#include
#include
#include "MeshServer.hh"
#include
#include "TableView.hh"
using namespace std;
FortuneServer::FortuneServer(QObject *parent)
: QTcpServer(parent)
{
}
void FortuneServer::procesServerString(string serverString){
emit procesServerStringToParent(serverString);
}
void FortuneServer::getStringToThread(string serverString){
emit getStringToThreadSignal(serverString);
}
void FortuneServer::incomingConnection(int socketDescriptor)
{
FortuneThread *serverthread = new FortuneThread(socketDescriptor, this);
//connect(&serverthread, SIGNAL(finished()), &serverthread, SLOT(deleteLater()));
QThread* thread = new QThread;
serverthread->moveToThread(thread);
connect(thread, SIGNAL(started()), serverthread, SLOT(getString()));
connect(serverthread, SIGNAL(fromThreadString(string)), this, SLOT(procesServerString(string)));
connect(this, SIGNAL(getStringToThreadSignal(string)), serverthread, SLOT(sendString(string)));
connect(serverthread, SIGNAL(finished()), thread, SLOT(quit()));
connect(serverthread, SIGNAL(finished()), serverthread, SLOT(deleteLater()));
connect(serverthread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
FortuneThread::FortuneThread(int socketDescriptor, QObject *parent)
: QObject(parent), socketDescriptor(socketDescriptor)
{
}
void FortuneThread::getString()
{
if (!tcpSocket.setSocketDescriptor(socketDescriptor)) {
emit error(tcpSocket.error());
cout<<"socket error"< return;
}
//in part
if(!tcpSocket.waitForReadyRead(10000)){
emit finished();
return;
}
int joj = tcpSocket.bytesAvailable();
char inbuffer[1024];
tcpSocket.read(inbuffer,1024);
string instring;
instring = inbuffer;
instring.resize(joj);
emit fromThreadString(instring);
}
void FortuneThread::sendString(string sendoutString)
{
//out part
char buffer[1024];
int buffer_len = 1024;
int bytecount;
memset(buffer, '\0', buffer_len);
string outstring = sendoutString;
int TempNumOne= (int)outstring.size();
for (int a=0;a {
buffer[a]=outstring[a];
}
QByteArray block;
block = buffer;
tcpSocket.write(block);
tcpSocket.disconnectFromHost();
tcpSocket.waitForDisconnected();
emit finished();
}

这是来自父母的:

//server start
QHostAddress adr;
adr.setAddress( QString("127.0.0.1") );
adr.toIPv4Address();
quint16 port = 1101;
if (!server.listen( adr, port)) {
QMessageBox::critical(this, tr("CR_bypasser"),
tr("Unable to start the server: %1.")
.arg(server.errorString()));
close();
return;
}
QString ipAddress;
ipAddress = server.serverAddress().toString();
statusLabel->setText(tr("The server is running on\n\nIP: %1\nport: %2\n\n"
"Run the Fortune Client example now.")
.arg(ipAddress).arg(server.serverPort()));
connect (&server, SIGNAL(procesServerStringToParent(string)), this, SLOT(procesServerString(string)));
connect (this, SIGNAL(StringToServer(string)), &server, SLOT(getStringToThread(string)));

编辑:我想做的事情:

我有一个客户端(游戏引擎(Cryengine)的一部分),我使用该客户端通过套接字发送游戏内坐标字符串和其他一些东西,例如其在我之前给出的链接中所做的.这样可以.我从“ 127.0.0.1”端口1101上获取数据.现在,我只需要在自己的程序中对此数据进行评估,该程序具有这个TableView类,在其中可以收集从字符串中获取的坐标,对坐标中的一些数据进行求值并然后将此新字符串通过服务器返回给gameengine.在游戏中,我将单击对象以获取其coor.,从中获得一个字符串(包含coor,entityid等),然后将该字符串发送到服务器,该服务器从TableView返回已调用信息.我只需要这种一种方式,仅使一个正在发送字符串的客户端流动.我不确定recv(hsock,buffer,buffer_len,0),我猜是负责游戏中字符串发送的节点会等待返回字符串吗?这是我真的很困惑的我的第一个程序atm …

解决方法:

您提供的代码是货物崇拜代码的示例:您做各种不必要的事情,显然是希望解决此问题.

可能的突发事件…

代码中存在很多问题,但是我认为导致崩溃的原因是:tcpSocket.write(block)不会在线路中发出零终止字符串.该块是零终止的,但是分配给字节数组不会将此零终止添加到QByteArray的size()中.即使字节数组的内容内部有一个零终止字节,下面的代码也会打印1.

QByteArray arr = "a";
qDebug("len=%d", arr.size());

接收代码期望零终止,但从不接收.然后,您继续为std :: string分配一个非零终止的缓冲区:

string instring;
instring = inbuffer;
instring.resize(joj);

随后的调整大小是对货物的崇拜:您正在尝试在std :: string&之后解决问题. std :: string :: operator =(const char *)很可能已经读过缓冲区.

但这并不意味着修复是正确的方法.一点也不.正确的做法是删除编写的代码并正确执行,而不会产生大量不必要的不​​必要的咒语.

…以及所有其他问题

您陷入了相信魔术的陷阱,在各种论坛中层出不穷.

线程不是不可思议的对象,您可以将它们应用于任何问题,希望它们能对您有所帮助.我不知道是什么使人们认为线程是神奇的,但是经验法则是:如果有人告诉您“哦,您应该尝试线程”,则很可能是错误的.如果他们告诉与网络相关的问题,那几乎是不对的,对他们没有帮助,而且他们根本不理解您的问题(看来您也不是).通常,除非您清楚地了解问题,否则线程将无济于事. Qt的网络系统是异步的:如果不使用waitxxxx()函数,它不会阻止代码的执行.顺便说一下,您不应该使用它们,所以这里一切都很好.无需庞大的线程.

因此,完全没有必要为每个传入的连接启动一个新线程.这将降低服务器的性能-尤其是在服务器进行简单处理的情况下,因为这会增加上下文切换和线程创建/拆除每个连接的开销.您希望系统中每个内核少于2个线程,因此对于池中的线程数使用QThread :: idealThreadCount()将是一个不错的起点.

您还剥夺了线程的好处,因为只使用网络线程来接收数据,然后发出fromThreadString(string)信号.我假设信号被发送到您的应用程序的主线程.现在这很愚蠢,因为从网络套接字接收一堆字节简直是微不足道的.您的线程不做任何工作,它们做的所有工作都浪费在创建和删除上.

下面的代码是一个简单示例,说明了如何正确使用Qt API来实现一种客户端服务器系统,该客户端服务器系统以循环方式在物理核心之间分配工作.它应该表现很好. Qt中包含的Fortune客户示例确实非常不幸,因为这恰恰是错误的处理方式.

人们会注意到的是:

>这并非完全无关紧要. Qt可能会更有用,但不是.
>客户端和发送方都从线程池移到线程中.
>断开连接的客户端不会被删除,而只会返回到客户端列表
放在踏板池旁.当需要客户端时,它们将被重用.
> QThread不是从其派生的. QTcpServer仅派生用于访问套接字句柄.
>不使用名称以wait()开头的函数.一切都是异步处理的.
> ThreadPool为客户端的newConnection(int)插槽保留查找的QMetaMethod.这比使用QMetaObject :: invokeMethod()更快,因为它每次都必须查找内容.
>在主线程中运行的计时器通过删除第一个发送方来启动信号插槽链.每个发件人的删除都会触发下一个发件人的删除.最终,最后一个发送者触发了线程池中的quit()插槽.当所有线程确实完成时,后者会发出finish()信号.

#include
#include
#include
#include
#include
#include
#include
// Processes data on a socket connection
class Client : public QObject
{
Q_OBJECT
public:
Client(QObject* parent = 0) : QObject(parent), socket(new QTcpSocket(this))
{
connect(socket, SIGNAL(readyRead()), SLOT(newData()));
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(newState(QAbstractSocket::SocketState)));
qDebug("Client()");
}
~Client() { qDebug("~Client()"); }
signals:
void done();
public slots:
void newConnection(int descriptor) {
socket->setSocketDescriptor(descriptor);
}
private slots:
void newData() {
QByteArray data = socket->readAll();
if (0) qDebug("got %d bytes", data.size());
if (0) qDebug("got a string %s", data.constData());
// here we can process the data
}
void newState(QAbstractSocket::SocketState state) {
qDebug("client new state %d", state);
if (state == QAbstractSocket::UnconnectedState) { emit done(); }
}
protected:
QTcpSocket* socket;
int descriptor;
};
// Connects to a client and sends data to it
class Sender : public QObject
{
Q_OBJECT
public:
Sender(const QString & address, quint16 port, QObject * parent = 0) :
QObject(parent), socket(new QTcpSocket(this)),
bytesInFlight(0), maxBytesInFlight(65536*8)
{
connect(socket, SIGNAL(stateChanged(QAbstractSocket::SocketState)),
SLOT(newState(QAbstractSocket::SocketState)));
connect(socket, SIGNAL(bytesWritten(qint64)), SLOT(sentData(qint64)));
socket->connectToHost(address, port);
qDebug("Sender()");
}
~Sender() { qDebug("~Sender()"); }
protected:
// sends enough data to keep a maximum number of bytes in flight
void sendData() {
qint64 n = maxBytesInFlight - bytesInFlight;
if (n <= 0) return;
bytesInFlight += n;
socket->write(QByteArray(n, 44)); // 44 is the answer, after all
}
protected slots:
void sentData(qint64 n) {
bytesInFlight -= n;
Q_ASSERT(bytesInFlight >= 0);
sendData();
}
void newState(QAbstractSocket::SocketState state) {
qDebug("sender new state %d", state);
if (state == QAbstractSocket::ConnectedState) sendData();
}
protected:
QTcpSocket* socket;
qint64 bytesInFlight;
qint64 maxBytesInFlight;
};
// Keeps track of threads and client objects
class ThreadPool : public QTcpServer
{
Q_OBJECT
public:
ThreadPool(QObject* parent = 0) : QTcpServer(parent), nextThread(0) {
for (int i=0; i QThread * thread = new QThread(this);
connect(thread, SIGNAL(finished()), SLOT(threadDone()));
thread->start();
threads < }
const QMetaObject & mo = Client::staticMetaObject;
int idx = mo.indexOfMethod("newConnection(int)");
Q_ASSERT(idx>=0);
method = mo.method(idx);
}
void poolObject(QObject* obj) const {
if (nextThread >= threads.count()) nextThread = 0;
QThread* thread = threads.at(nextThread);
obj->moveToThread(thread);
}
protected:
void incomingConnection(int descriptor) {
Client * client;
if (threads.isEmpty()) return;
if (! clients.isEmpty()) {
client = clients.dequeue();
} else {
client = new Client();
connect(client, SIGNAL(done()), SLOT(clientDone()));
}
poolObject(client);
method.invoke(client, Q_ARG(int, descriptor));
}
signals:
void finished();
public slots:
void quit() {
foreach (QThread * thread, threads) { thread->quit(); }
}
private slots:
void clientDone() {
clients.removeAll(qobject_cast(sender()));
}
void threadDone() {
QThread * thread = qobject_cast(sender());
if (threads.removeAll(thread)) delete thread;
if (threads.isEmpty()) emit finished();
}
private:
QList threads;
QQueue clients;
QMetaMethod method;
mutable int nextThread;
};
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ThreadPool server;
if (!server.listen(QHostAddress::Any, 1101)) qCritical("cannot establish a listening server");
const int senderCount = 10;
Sender *prevSender = 0, *firstSender = 0;
for (int i = 0; i Sender * sender = new Sender("localhost", server.serverPort());
server.poolObject(sender);
if (!firstSender) firstSender = sender;
if (prevSender) sender->connect(prevSender, SIGNAL(destroyed()), SLOT(deleteLater()));
prevSender = sender;
}
QTimer::singleShot(3000, firstSender, SLOT(deleteLater())); // run for 3s
server.connect(prevSender, SIGNAL(destroyed()), SLOT(quit()));
qApp->connect(&server, SIGNAL(finished()), SLOT(quit()));
// Deletion chain: timeout deletes first sender, then subsequent senders are deleted,
// finally the last sender tells the thread pool to quit. Finally, the thread pool
// quits the application.
return a.exec();
}
#include "main.moc"

根据您的解释,您的游戏引擎将启动并创建与本地主机上某个端口的连接.您的Qt程序应该在端口1101上接受该连接,接收一些字符串,对其进行处理,然后将其发送回去.

修改代码以接受固定端口号上的连接.所有数据处理,包括将响应发送回,都必须从newData()插槽完成.如果您的计算非常复杂,也可以将该数据传递给其他线程.复数是指成千上万的运算(例如加法和乘法)或成千上万的trig运算.

Sender类仅作为示例.当然,您的游戏引擎会执行发送,因此您不需要Sender类.


推荐阅读
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文讨论了使用差分约束系统求解House Man跳跃问题的思路与方法。给定一组不同高度,要求从最低点跳跃到最高点,每次跳跃的距离不超过D,并且不能改变给定的顺序。通过建立差分约束系统,将问题转化为图的建立和查询距离的问题。文章详细介绍了建立约束条件的方法,并使用SPFA算法判环并输出结果。同时还讨论了建边方向和跳跃顺序的关系。 ... [详细]
  • 如何自行分析定位SAP BSP错误
    The“BSPtag”Imentionedintheblogtitlemeansforexamplethetagchtmlb:configCelleratorbelowwhichi ... [详细]
  • Java太阳系小游戏分析和源码详解
    本文介绍了一个基于Java的太阳系小游戏的分析和源码详解。通过对面向对象的知识的学习和实践,作者实现了太阳系各行星绕太阳转的效果。文章详细介绍了游戏的设计思路和源码结构,包括工具类、常量、图片加载、面板等。通过这个小游戏的制作,读者可以巩固和应用所学的知识,如类的继承、方法的重载与重写、多态和封装等。 ... [详细]
  • 本文介绍了设计师伊振华受邀参与沈阳市智慧城市运行管理中心项目的整体设计,并以数字赋能和创新驱动高质量发展的理念,建设了集成、智慧、高效的一体化城市综合管理平台,促进了城市的数字化转型。该中心被称为当代城市的智能心脏,为沈阳市的智慧城市建设做出了重要贡献。 ... [详细]
  • 本文讨论了一个关于cuowu类的问题,作者在使用cuowu类时遇到了错误提示和使用AdjustmentListener的问题。文章提供了16个解决方案,并给出了两个可能导致错误的原因。 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 关键词:Golang, Cookie, 跟踪位置, net/http/cookiejar, package main, golang.org/x/net/publicsuffix, io/ioutil, log, net/http, net/http/cookiejar ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • Linux环境变量函数getenv、putenv、setenv和unsetenv详解
    本文详细解释了Linux中的环境变量函数getenv、putenv、setenv和unsetenv的用法和功能。通过使用这些函数,可以获取、设置和删除环境变量的值。同时给出了相应的函数原型、参数说明和返回值。通过示例代码演示了如何使用getenv函数获取环境变量的值,并打印出来。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了PE文件结构中的导出表的解析方法,包括获取区段头表、遍历查找所在的区段等步骤。通过该方法可以准确地解析PE文件中的导出表信息。 ... [详细]
author-avatar
风里火
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有