• 11273阅读
  • 5回复

[提问]Qt TcpSocket多线程诡异问题求解... [复制链接]

上一主题 下一主题
离线a289672082
 

只看楼主 倒序阅读 楼主  发表于: 2016-05-16
  1. #include <QtWidgets/QMainWindow>
  2. #include "QGridLayout"
  3. #include "QVBOXlAYOUT"
  4. #include "QPushButton"
  5. #include "QLineEdit"
  6. #include "Qlabel"
  7. #include <QTcpSocket>
  8. #include <QHostAddress>
  9. #include <QMessageBox>
  10. #include <functional>
  11. #include <QTcpServer>
  12. #include "mythread.h"
  13. class MyWindow : public QWidget
  14. {
  15.     Q_OBJECT
  16. public:
  17.     QTcpServer* server;
  18.     MyWindow(QWidget *parent = 0);
  19.     ~MyWindow();
  20.     QPushButton *  btn;
  21.     QLabel* label;
  22.     QLineEdit* edit;
  23.     QVBoxLayout* Vbox;
  24.     QGridLayout* grid;
  25.      signals:
  26.     void mainwrite(QString);
  27.     public slots:
  28.     void On_TestBtn_Cliked();
  29.     void  acceptConnection();
  30. };

  1. MyWindow::MyWindow(QWidget *parent)
  2.     : QWidget(parent)
  3. {
  4.     
  5.     
  6.     label = new QLabel(QStringLiteral(""));
  7.     btn  = new QPushButton("send");
  8.     edit = new QLineEdit();
  9.     grid = new QGridLayout();
  10.     grid->addWidget(edit,0,0);
  11.     grid->addWidget(btn,0,1);
  12.     Vbox = new QVBoxLayout();
  13.     Vbox->addLayout(grid);
  14.     Vbox->addWidget(label);
  15.      setLayout(Vbox);
  16.     
  17.     fuc1 fu = std::bind(&MyWindow::On_TestBtn_Cliked, this);
  18.     connect(btn, &QPushButton::clicked, this, fu);
  19.     server = new QTcpServer(this);
  20.     server->listen(QHostAddress::Any, 6665);
  21.     connect(server, SIGNAL(newConnection()), this, SLOT(acceptConnection()));
  22.     
  23. }
  24. void MyWindow::acceptConnection()
  25. {
  26.     qDebug() << "main id:" << QThread::currentThreadId();
  27.     QTcpSocket*  clientConnection = server->nextPendingConnection();
  28.     qDebug() << __LINE__;
  29.     MyWork*  thread_Tmp = new MyWork(clientConnection->socketDescriptor(),NULL);
  30.     connect(this, &MyWindow::mainwrite, thread_Tmp, std::bind(&MyWork::writeslot, thread_Tmp, std::placeholders::_1));
  31.     qDebug() << __LINE__;
  32.   
  33.   all.append(thread_Tmp);
  34.     
  35. }  
  36. MyWindow::~MyWindow()
  37. {
  38. }
  39. #include <QEvent>
  40. #include <QApplication>
  41. void MyWindow::On_TestBtn_Cliked()
  42. {
  43.     qDebug() << "write fuc";
  44.     emit mainwrite(edit->text());
  45.   
  46. }
线程中接收数据问题,发送数据第二次出现问题,尝试了各种方法。。。
  1. class   MyWork :public QObject
  2. {
  3.     Q_OBJECT
  4. public:
  5.     QThread * m_thread;
  6.     QTcpSocket* socket;
  7.     int m_socketid;
  8.     MyWork(int socketid, QObject* parent = NULL);
  9.     ~MyWork();
  10.     public slots:
  11.     void readClient();
  12. signals:
  13.     void wirte(QString);
  14.     public slots :
  15.     void writeslot(QString);
  16. private:
  17. };
  1. MyWork::MyWork(int socketid, QObject* parent) :QObject(parent)
  2. {
  3.     socket = NULL;
  4.     m_socketid = socketid;
  5.     m_thread = new QThread();
  6.     socket = new QTcpSocket();
  7.     socket->setSocketDescriptor(this->m_socketid);
  8.     connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()), Qt::DirectConnection);
  9.     this->moveToThread(m_thread);
  10.     m_thread->start();
  11. }
  12. void MyWork::readClient()
  13. {
  14.     qDebug() << "thread get msg id:" << QThread::currentThreadId() << "read:" << socket->readAll();
  15. }
  16. void MyWork::writeslot(QString s)
  17. {
  18.     qDebug() << "writeslot  id:" << QThread::currentThreadId();
  19.     socket->write(s.toStdString().c_str());
  20.   [backcolor=#ffffff][color=#008ef1]   socket->waitForBytesWritten(); //这行代码会导致 套接字[9904]QSocketNotifier:从另一个线程通知不能启用或禁用  但是注释会导致发送过一次数据 下次就无法发送[/color][/backcolor]
  21.     qDebug() << "wait write end";
  22. }
  23. MyWork::~MyWork()
  24. {
  25. }

帮我看看
   socket->waitForBytesWritten(); //这行代码会导致 套接字[9904]QSocketNotifier:从另一个线程通知不能启用或禁用  但是注释会导致发送过一次数据 下次就无法发送
的诡异问题,谢谢各位了
通过按钮触发socket发送数据,Qobject不能跨线程调用,因此用MovetoThread了,但是问题依旧,然后尝试了QEvent,问题依旧。Qt socket只能在线程内部写入吗,必须得用底层的API实现socket吗
接收和发送的函数打印出来都是在线程中,为啥还有这个问题呐!



离线lemonzll

只看该作者 1楼 发表于: 2016-05-16
代码我没试过,有点问题,MyWork里面socket的parent没有设置,调用moveToThread的时候socket没有切换到其他线程,你在writeSlot里面调用write的时候socket就跨线程调用了,这样会有警告。还有就是MyWork里面你不要这样根据线程描述符重建socket,直接还用原来的socket就可以
离线jxgyzhang

只看该作者 2楼 发表于: 2016-05-16
楼上说的对你也可以把socket也移动到新的线程中去
    socket = NULL;
    m_socketid = socketid;
    m_thread = new QThread();
    socket = new QTcpSocket();
    socket->setSocketDescriptor(this->m_socketid);
    connect(socket, SIGNAL(readyRead()), this, SLOT(readClient()), Qt::DirectConnection);
    socket ->moveToThread(m_thread);
    this->moveToThread(m_thread);
    m_thread->start();
离线a289672082

只看该作者 3楼 发表于: 2016-05-16
回 lemonzll 的帖子
lemonzll:代码我没试过,有点问题,MyWork里面socket的parent没有设置,调用moveToThread的时候socket没有切换到其他线程,你在writeSlot里面调用write的时候socket就跨线程调用了,这样会有警告。还有就是MyWork里面你不要这样根据线程描述符重建socket,直接还用原来的socket就可以 (2016-05-16 08:37) 

谢谢  我现在试试
离线a289672082

只看该作者 4楼 发表于: 2016-05-16
回 jxgyzhang 的帖子
jxgyzhang:楼上说的对你也可以把socket也移动到新的线程中去
    socket = NULL;
    m_socketid = socketid;
    m_thread = new QThread();
    socket = new QTcpSocket();
....... (2016-05-16 09:49) 

谢谢  我现在去试试
离线a289672082

只看该作者 5楼 发表于: 2016-05-16
@jxgyzhang    @lemonzll    两位  问题解决了  是socket没有指定parent.

代码改成:
m_thread = new QThread();
socket = new QTcpSocket(this);
socket->setSocketDescriptor(this->m_socketid);
就没问题了

总结:moveToThread,要小心,不能跨线程的对象不指定parent也属于跨线程操作
本帖提到的人: @jxgyzhang @lemonzll
快速回复
限100 字节
 
上一个 下一个