QTCreatot做一个多线程服务器,通信有问题

Toney_Ho CSDN会员 Toney_Ho 墨衍会员 · AI 创作全网分发 墨衍智能分发 通过墨衍一键同步至各平台 可同步平台 CSDN微信公众号微博知乎掘金百家号博客园抖音小红书 你的文章也可以这样分发 墨衍会员 ¥399起/年,写一次发全网 我也要 + 加入社区
QTCreator 做一个多线程TCP服务器,客户端以前别人就做好了,并定制了通信协议,现在我要用QT做一个服务器,要求能同时和多个客户机按通信协议通信。遇到了点问题,我调了很久都没解决,大家帮我看看。
通信协议是:
1. 服务器向客户机发送命令(GET);
2. 客户机发送START确认开始通信;
3. 服务器发送AGAIN允许客户机发送;
4. 接收客户机发送过来的信息并保存到缓冲区(QString)中;
5. 检索缓冲区有没有客户机发送过来的结束命令(FINISH);
6. 有:发送接收成功标志(SUCCESS)结束通信,存文件;
7. 没有:转3;
如此往复直到检索到缓冲区中有客户机发过来的结束标志。
服务器要求能同时向多个客户机发送GET命令,并发的接收客户机发过来的信息,并在收到结束标志后将收到的信息存文件,信息不能发生串扰。
我的思路:
1. 利用QT的多线程;
2. 并不是为每个连接上的用户开启一个线程,而是为每个需要通信的客户端开启一个线程;
3. 程序有GUI界面,每当有一个客户机连接到服务器以后在GUI上显示出来,并提供复选框,由用户勾选需要通信的客户端,并通过点击Get按钮向所选择的客户端发送GET命令,进行通信和信息处理;
问题是:
当我向多个客户发送GET的时候,程序偶尔会崩溃,偶尔成功但是保存的数据发生串扰(比如本来是客户1的数据却保存到了客户2的文件中)。我调了很久,没解决。
在线程的run()函数中:connect(sockfd, SIGNAL(readyRead()), this,SLOT(recvData()),Qt::DirectConnection);指定为Qt::DirectConnectio,那么recvData(),是否是在子线程之中执行?但是如果我指定为Qt::BlockingQueuedConnection程序通信依然存在问题。请问大家我的设计思想有没有问题,实现方法有没有问题。
主要代码如下,另附上源码包,http://download.csdn.net/detail/toney_ho/4058244
,大家可以下载下来调试运行一下,看是哪儿的问题,可能下载下来在QTCreator中容易看清楚点。
可能程序较长,大家耐心看一下共同进步。
//tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include "tcpthread.h"
#include <QTcpServer>
class tcpserver : public QTcpServer
{
Q_OBJECT
public:
explicit tcpserver(QObject *parent = 0);
//QList<int> clientDescriptorList;
signals:
void newRow(int);
void displayInfo(int,QString, int);
void updateBar(int, qint64);
void signal_send_command(int,int);
public slots:
void incomingConnection(int socketDescriptor);
void slot_send_command(int,int);
};
#endif
//tcpthread.h
#ifndef TCPTHREAD_H
#define TCPTHREAD_H
#include <QThread>
#include <QTcpSocket>
#include <QtNetwork>
#define SEND_AGIAN 2
#define FOUND_FINISH 3
#define SEND_SUCCESS 4
#define SEND_GET 10
#define FOUND_START 11
#define TEST_OTHER 98
#define DISPLAY_BUFFER 97
#define RECV_FILE_SUCCESS 99
#define SAVE_FILE_SUCCESS 100
#define GET "GET"
#define START "START"
#define AGAIN "AGIAN"
#define FINISH "FINISH"
#define SUCCESS "SUCCESS"
class QFile;
class QTcpSocket;
class TcpThread : public QThread
{
Q_OBJECT
public:
TcpThread(int socketDescriptor,int command, QObject *parent = 0);
void run();
QTcpSocket *sockfd;
int socketDescriptor;
int command;
signals:
void error(QTcpSocket::SocketError socketError);
void displayInfo(int,QString, int);
void updateBar(int, qint64);
public slots:
int processBuffer(QString );
void recvData();
};
#endif // TCPTHREAD_H
//widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "tcpthread.h"
#include "tcpserver.h"
class QDialogButtonBox;
class QTcpSocket;
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
TcpThread *thread ;
private:
Ui::Widget *ui;
tcpserver tcpServer;
QTime *currenttime;
private slots:
void on_pushButtonClearLog_clicked();
void on_pushButtonSaveLog_clicked();
void on_quitButton_clicked();
void on_pushButtonGET_clicked();
void on_OkButton_clicked();
void addNewRow(int);
void displayInfo(int,QString, int);
void updateBar(int, qint64);

signals:
void signal_send_command(int, int);

};
#endif // WIDGET_H
//tcpserver.cpp
#include "tcpserver.h"
//构造函数
tcpserver::tcpserver(QObject *parent) :
QTcpServer(parent)
{
}
//重新定义了incomingConnection这个虚函数,
//开辟一个新的tcpsocket线程,从TcpServer获得socketDescriptor,
//并完成相应的信号连接
void tcpserver::incomingConnection(int socketDescriptor)
{
qDebug() <<socketDescriptor;
//clientDescriptorList.append(socketDescriptor);
emit newRow(socketDescriptor); //display new client
connect(this,SIGNAL(signal_send_command(int ,int)),this,SLOT(slot_send_command(int ,int)));
}
void tcpserver::slot_send_command(int sockDescriptor, int cmd)
{
TcpThread *thread = new TcpThread(sockDescriptor,cmd, this);
thread->start();
connect(thread,SIGNAL(finished()),this,SLOT(deleteLater()));
connect(thread,SIGNAL(displayInfo(int,QString,int)),this,SIGNAL(displayInfo(int,QString,int)));
connect(thread,SIGNAL(updateBar(int,qint64)),this,SIGNAL(updateBar(int,qint64)));
}
//tcpthread.cpp
#include "tcpthread.h"
#include <QtGui>
#include <QtNetwork>
//构造函数完成简单的赋值/
TcpThread::TcpThread(int socketDescriptor,int command, QObject *parent):
QThread(parent),socketDescriptor(socketDescriptor),command(command)
{
}

void TcpThread::run()
{
sockfd = new QTcpSocket;
if (!sockfd->setSocketDescriptor(socketDescriptor))
{
emit error(sockfd->error());
return;
}
sockfd -> write(GET);
emit this->displayInfo(socketDescriptor,sockfd->peerAddress().toString(), SEND_GET);
connect(sockfd, SIGNAL(readyRead()), this,SLOT(recvData()),Qt::DirectConnection);
exec();
}

void TcpThread::recvData() //接收数据
{
static qint64 bytesReceived = 0 ; //收到的总字节
static QString buffer = ""; //数据缓冲区

qint64 available = 0;
if ( ( available = sockfd ->bytesAvailable() ) > 0 )
{
bytesReceived += available;
buffer.append(sockfd ->readAll());

//更新进度条
emit this->updateBar(socketDescriptor, bytesReceived);
//display buffer
emit this->displayInfo(socketDescriptor,buffer, DISPLAY_BUFFER);

if ( processBuffer(buffer) == 1)
{
emit this->updateBar(socketDescriptor, 100); //更新进度条
goto GOTO_SEND_SUCCESS;
}
goto GOTO_SEND_AGAIN;

GOTO_SEND_SUCCESS:
//send SUCCESS
sockfd -> write(SUCCESS);
emit this-> displayInfo(socketDescriptor,sockfd->peerAddress().toString(), SEND_SUCCESS);
return;

GOTO_SEND_AGAIN:
//send AGIAN
emit this->displayInfo(socketDescriptor,sockfd->peerAddress().toString(), SEND_AGIAN);
if (-1 == sockfd -> write(AGAIN))
{
qDebug() << "write error";
return;
}
}
}

int TcpThread::processBuffer(QString buffer)
{
static int END_FLAG_FINISH = 0 ;
static int positionSTART = 0;
static int positionFINISH = 0;
static QHostAddress fileName ;
static QFile *localFile ;
static QString fileBuffer = ""; //file buffer

END_FLAG_FINISH = 0;
if (-1 != (positionSTART = buffer.indexOf(START)) ) //found START
{
if (-1 != (positionFINISH = buffer.indexOf(FINISH))) //found FINISH
{
emit this->displayInfo(socketDescriptor,sockfd->peerAddress().toString(), FOUND_FINISH);
END_FLAG_FINISH = 1;
fileBuffer = buffer.mid(positionSTART+36,positionFINISH -positionSTART - 36);

fileName = sockfd->peerAddress();
quint16 port = sockfd->peerPort();
localFile = new QFile(fileName.toString()+(tr(".%1").arg(port))); //用户端的IP地址作为保存文件名
if(!localFile->open(QFile::WriteOnly))
{
qDebug() << "open file error!";
return -1;
}
QByteArray filetemp = fileBuffer.toLatin1();
if ( -1 == ( localFile->write(filetemp.data(),qstrlen(filetemp.data()))))
{
qDebug() <<"write file error!";
}
localFile->close();
fileBuffer.clear();
emit this->displayInfo(socketDescriptor,sockfd->peerAddress().toString(), SAVE_FILE_SUCCESS);
return END_FLAG_FINISH;
}
}
return END_FLAG_FINISH;
}

...全文
评论 18
收藏 已收藏
分享
返回顶部
Toney_Ho CSDN会员
Qt 21,503 成员 26,693 内容