当前位置:   article > 正文

在QT中利用TCP协议实现多线程的传输文件_qt 建立多个tcpsocket同时通信

qt 建立多个tcpsocket同时通信

目录 

目录

前言

一、主要功能

二、基于QT的TCP套接字通信

1.服务器端通信流程

2.客户端通信流程

三、基于QT的多线程

1.创建流程

四、源码

五、踩坑记录


前言

本文在QT中利用TCP协议实现了一个多线程的文件互传系统,其中遇到了不少槽点,甚至还有很多亟待解决的问题,因此想写一篇博文来记录一下。


一、主要功能

  • 服务器端显示在线的客户端列表

因为运用了多线程,所以可以支持多个客户端同时登陆,服务器主界面也不会陷入假死状态。

  • 服务器端可指定某一用户进行文件发送

鼠标选中后,进行发送即可。 

  • 所有在线客户端可以同时对服务器端进行发送文件的操作

二、基于QT的TCP套接字通信

1.服务器端通信流程

(1)创建一个TCP服务器对象

我这里是新建了一个myTcpServer的类,该类继承自QTcpServer。

  1. #ifndef MYTCPSERVER_H
  2. #define MYTCPSERVER_H
  3. #include <QTcpServer>
  4. class myTcpServer : public QTcpServer
  5. {
  6. Q_OBJECT
  7. public:
  8. explicit myTcpServer(QObject *parent = nullptr);
  9. protected:
  10. void incomingConnection(qintptr handle) override;
  11. signals:
  12. void sendDescriptor(qintptr handle);
  13. public slots:
  14. };
  15. #endif // MYTCPSERVER_H

(2)实例化myTcpServer对象,并对服务器的IP和端口设置监听

  1. //实例化myTcpServer对象,用重写incomingConnection的方式获取通讯socket
  2. m_serverRecv = new myTcpServer(this);
  3. m_serverSend = new myTcpServer(this);
  4. //设置监听ip和端口
  5. m_serverRecv->listen(QHostAddress::AnyIPv4,port);
  6. m_serverSend->listen(QHostAddress::AnyIPv4,port);

 (3)在myTcpServer中重写incomingConnection函数

每当有新连接的时候,会自动触发该函数,并获得一个与该连接通信的描述符。

  1. #include "mytcpserver.h"
  2. myTcpServer::myTcpServer(QObject *parent) : QTcpServer(parent)
  3. {
  4. }
  5. //创建一个class,并继承qtcpserver,重写其中的incomingConnection函数,每当有新连接时执行下面的函数
  6. void myTcpServer::incomingConnection(qintptr handle)
  7. {
  8. //给主线程发送一个信号,并传递描述符
  9. emit sendDescriptor(handle);
  10. }

(4)创建通信套接字对象(QTcpSocket)

创建一个通信套接字对象(QTcpSocket),并将上面获得的描述符写入。

  1. //创建套接字
  2. m_socket = new QTcpSocket;
  3. //写入描述符
  4. m_socket->setSocketDescriptor(handle);

(5)利用通信套接字对象和客户端进行数据传输

  1. //读
  2. fileData = m_socket->read(65536);
  3. //写
  4. m_socket->write((char*)&fileNameSize,4);

2.客户端通信流程

(1)创建通信的套接字类 QTcpSocket 对象

(2)绑定和连接服务器的IP地址和端口

  1. //创建套接字
  2. m_socket = new QTcpSocket;
  3. //绑定和连接
  4. m_socket->connectToHost(QHostAddress(ip),port);

(3)利用通信套接字对象和客户端进行数据传输

三、基于QT的多线程

1.创建流程

(1)创建一个工作类,继承QObject,将线程函数写在public中

 (2)实例化工作类和线程

注意工作类不要指定父组件。

  1. //实例化一个发送文件的工作类
  2. sendWork* sendWorker = new sendWork;
  3. //实例化一个发送线程
  4. m_sendThread = new QThread;

(3)将工作类移入线程中,启动线程

  1. //将工作类挪入线程中
  2. sendWorker->moveToThread(m_sendThread);
  3. //启动线程
  4. m_sendThread->start();

(4)用信号槽在主线程激活子线程的线程函数

注意不要在主线程直接调用线程函数,一定要用信号槽,否则函数依然在主线程中执行

  1. //连接子线程的工作函数
  2. connect(this,&MainWindow::sendStart,sendWorker,&sendWork::sendFiles);
  3. //发射信号激活工作函数并传递通信描述符
  4. emit sendStart(handle);

四、源码

(62条消息) QT中利用TCP协议实现了一个多线程的文件互传系统-C++文档类资源-CSDN文库https://download.csdn.net/download/qdeeafafasaa/85594998

源码放在这里了,0积分,有需要请大家自取

五、踩坑记录

  1. 不要在线程间传递QTcpSocket套接字对象,如果想在子线程中进行传输,一定不要在主线程中创建套接字后,再通过其它方式传入子线程,这样会导致不可预知的错误,一定要在你使用的子线程里创建对象。
  2. 使用readyread信号判断有没有数据输入时,要注意不是对方调用几次write,就会来几次readyread,有可能write次数较快,readyread信号会重叠在一起。建议用bytesAvailable()获取缓存内还未读取的字节数,然后两者一起配合使用
  3. 本文在服务器端接收数据和发送数据分别使用了两个端口,本身考虑使用一个端口,但是在数据收发时会有触发不了readyread信号的情况产生。
  4. 在使用多线程进行数据收发时,用信号槽触发工作函数,如果不在信号激活后马上进行disconnect,有可能会导致一个信号多次触发工作函数。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/187344
推荐阅读
相关标签
  

闽ICP备14008679号