当前位置: 代码迷 >> QT开发 >> QTCreatot做一个多线程服务器,通信有有关问题
  详细解决方案

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

热度:125   发布时间:2016-04-25 05:04:52.0
QTCreatot做一个多线程服务器,通信有问题
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中容易看清楚点。
可能程序较长,大家耐心看一下共同进步。
C/C++ code
//tcpserver.h#ifndef TCPSERVER_H#define TCPSERVER_H#include "tcpthread.h"#include <QTcpServer>class tcpserver : public QTcpServer{    Q_OBJECTpublic:    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_OBJECTpublic:    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_OBJECTpublic:    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;}
  相关解决方案