QT+多线程TCP服务器+进阶版

打印 上一主题 下一主题

主题 1002|帖子 1002|积分 3008

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
        针对之前的服务器,如果子线程工作类内里必要使用socket发送消息,必须要使用信号与槽的方法, 先发送一个信号给父进程,父进程调用socket发送消息(缘故原由是QT防止父子进程抢夺同一资源,因此直接规定父子进程不能使用同一资源,大概很单方面,但至少针对socket这个类是这样的),因此,为了更好的使用多线程TCP服务器,下面介绍一种新的方法。
1、新建一个编译无错误的工程
2、在pro文件中加入network

3、新建两个类,一个Worker类继承QObject,一个TcpServer类继承QTcpServer

4、编辑服务器界面

5、给控件命名
6、查找本地有用的IPV4,并用combox控件表现
  1.     QList<QHostAddress> ipAddressesList = QNetworkInterface::allAddresses();
  2.     for (int i = 0; i < ipAddressesList.size(); ++i) {
  3.         if (!ipAddressesList.at(i).isNull()//IP地址是否为NULL
  4.             && ipAddressesList.at(i).toIPv4Address() != 0//是否是IPV4地址
  5.             )
  6.         {
  7.             ui->IPComboBox->addItem(ipAddressesList.at(i).toString());
  8.         }
  9.     }
复制代码
7、创建Server对象,绑定毗连服务器按钮和创建代码
  1. #include "tcpserver.h"
  2. TcpServer *tcpserver = NULL;//TcpServer这个是自定义的服务器类
  3. void Widget::on_connectPushButton_clicked()
  4. {
  5.     if(ui->connectPushButton->text().contains("打开服务器"))
  6.     {
  7.         tcpserver = new TcpServer();           //实例化tcpserver对象
  8.         tcpserver->listen( QHostAddress(ui->IPComboBox->currentText()),ui->portLineEdit->text().toInt());//进行IP地址与端口的监听
  9.         ui->connectPushButton->setText("断开服务器");
  10.     }
  11.     else
  12.     {
  13.         tcpserver->close();
  14.         ui->connectPushButton->setText("打开服务器");
  15.     }
  16. }
复制代码
8、当客户端被毗连时,TcpServer类会自己调用incomingConnection方法,然后我们必要重写这个方法,首先就是新建一个工作类,然后把套接字文件符传送过去,然后在构造函数初始化套接字
  1. protected:
  2.     void incomingConnection(qintptr socketDescriptor) override; //当客户端连接时被调用。
复制代码
  1. void TcpServer::incomingConnection(qintptr socketDescriptor)
  2. {
  3.     QThread *thread = new QThread();
  4.     Worker *worker = new Worker(socketDescriptor);//socketDescriptor这个参数时套接字的描述符,用于生成套接字socket
  5.     connect(thread, &QThread::finished, thread, &QThread::deleteLater); //释放线程资源
  6.     worker->moveToThread(thread);
  7.     thread->start();
  8. }
复制代码
 9、先修改工作类worker的构造函数,将套接字描述符加入
  1. public:
  2.     explicit Worker(qintptr socketDescriptor,QObject *parent = nullptr);
  3. Worker::Worker(qintptr socketDescriptor, QObject *parent)
  4.     : QObject{parent}
  5. {
  6.     m_socketDescriptor=socketDescriptor;
  7.     m_tcpsocket = new QTcpSocket(this);
  8.     m_tcpsocket->setSocketDescriptor(m_socketDescriptor);
  9. }
复制代码
10、获取套接字之后开始处理读到的数据,在工作类中建立读信号和槽函数关系
  1. public slots:
  2.     void onReadyRead();
  3. connect(m_tcpsocket,&QTcpSocket::readyRead,this,&Worker::onReadyRead);
  4. void Worker::onReadyRead()
  5. {
  6.     QByteArray data = m_tcpsocket->readAll();
  7.     m_tcpsocket->write("receive : "+data);
  8. }
复制代码
12、编译通过,且毗连成功,可以将收到的消息发给服务器

 13、开始处剃头送信息的消息,首先Widget界面有一个发送按钮,用于发送数据给客户端,代码现实操纵时发送信号给工作类处理
  1. signals:
  2.     void sendDataSignals(QString data);
  3. void Widget::on_sendPushButton_clicked()
  4. {
  5.     emit sendDataSignals(ui->sendPlainTextEdit->toPlainText());
  6. }
复制代码
我们如何让Widget和worker工作类产生接洽,利用中心类TcpServer,我们先将sendDataSignals信号发送到TcpServer类中,利用connect信号转信号,然后等待TcpServer发送 sendDataSignals信号时绑定Worker类的槽函数进行发送数据
  1. connect(this,&Widget::sendDataSignals,tcpserver,&TcpServer::sendDataSignals);
复制代码
  1. connect(this,&TcpServer::sendDataSignals,worker,&Worker::sendData_slots);
复制代码
  1. void Worker::sendData_slots(QString data)
  2. {
  3.      m_tcpsocket->write("send : "+data.toUtf8()+"\r\n");
  4. }
复制代码
 14、编译代码,运行成功,可以成功收发数据

15、当吸收到数据后我们让其在网络数据吸收窗口表现,采用信号与槽的机制
  1. void Worker::onReadyRead()
  2. {
  3.     QByteArray data = m_tcpsocket->readAll();
  4.     m_tcpsocket->write("i am server,receive : "+data+"\r\n");
  5.     emit readDisplaySignals(QString::fromUtf8(data));
  6. }
复制代码
  1. connect(worker,&Worker::readDisplaySignals,this,&TcpServer::readDisplaySignals);
复制代码
  1. connect(tcpserver,&TcpServer::readDisplaySignals,this,&Widget::readDataDisplay_slots);
复制代码
  1. void Widget::readDataDisplay_slots(QString data)
  2. {
  3.     QString str=ui->receivePlainTextEdit->toPlainText();//接收区之前的内容
  4.     QDateTime nowtime = QDateTime::currentDateTime();
  5.     str += "[" + nowtime.toString("yyyy-MM-dd hh:mm:ss") + "] "+ "RX: ";//记录当前时间
  6.     str = str + data + "\r\n";//当前接收最新消息
  7.     ui->receivePlainTextEdit->setPlainText(str);
  8. }
复制代码
16、测试成功

17、完备工程代码
链接:https://pan.baidu.com/s/1wqfFoLKSrARjDHIX0Y-diQ?
提取码:生日

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

南七星之家

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表