qtcpserver用法_qt tcpserver

2022-10-03 15:35:07 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

QTcpServer和QTcpSocket使用详解


1、基本使用方法

QTcpServer和QTcpSocket的使用是密不可分的,所以两者一块演示使用方法。

QTcpServer常用信号:

  • newConnection()信号,该信号用于处理新接入的连接

QTcpSocket常用信号:

  • disconnected():断开连接后会触发该信号,一般在该信号的槽函数内处理内存清理释放等工作
  • readyRead():数据到达信号,在该信号的槽函数内处理数据接收

补充:如果想要获取远程接入的IP地址端口等信息,可以使用QTcpSocket的peerAddress()函数获取IP地址,peerPort()获取端口。

基于QTcpServer的TCP服务器多接入echo代码demo:

代码语言:javascript复制
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
namespace Ui { 

class Widget;
}
class Widget : public QWidget
{ 

Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private:
Ui::Widget *ui;
private:
QTcpServer* tcpServer;
private slots:
void slotReadyRead();
void slotNewConnected();
};
#endif // WIDGET_H
代码语言:javascript复制
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{ 

ui->setupUi(this);
tcpServer = new QTcpServer(this);
QObject::connect(tcpServer, SIGNAL(newConnection()), this, SLOT(slotNewConnected()));
tcpServer->listen(QHostAddress::Any, 10126);
}
Widget::~Widget()
{ 

delete ui;
}
void Widget::slotNewConnected()
{ 

while(tcpServer->hasPendingConnections())
{ 

QTcpSocket* socket = tcpServer->nextPendingConnection();
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
QObject::connect(socket, SIGNAL(disconnected()), socket, SLOT(deleteLater()));
qDebug("[%s:%d] connected", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort());
}
}
void Widget::slotReadyRead()
{ 

QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());  // 取得信号发送者对象
socket->write(socket->readAll());                          // 将数据在发送回去
}

2、基于多线程的使用

~~~~~~~~ 处理网络的数据一般不会是单线程处理,因为要更新UI界面且还有任务,不可能让tcpSocket死等接收,正常情况下通过QTcpServer获得新接入的客户端QTcpSocket对象来进行收发数据操作,新接入一个连接就创建一个新的线程去处理,但是这里有一个问题就是 QTcpSocket是不支持跨线程调用的,哪怕是以引用或者指针的形式传入到子线程中,也是报错跨线程调用!

~~~~~~~~ 要想实现多线程则需要继承QTcpServer去重写incomingConnection函数,在该函数中将socketDescriptor参数用信号把他发射出来,或者直接在该函数中创建自己的任务处理线程,在线程中使用QTcpSocket类的setsetSocketDescriptor函数初始化一个socket就可以了。示例代码如下:

代码语言:javascript复制
#ifndef QMULTITCPSERVER_H
#define QMULTITCPSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QHostAddress>
class QMultiTcpServer : public QTcpServer
{ 

Q_OBJECT
public:
QMultiTcpServer(QObject* parent = nullptr);
virtual ~QMultiTcpServer();
public:
bool listen(const QHostAddress &address, quint16 port);
protected:
void incomingConnection(int socketDescriptor);
signals:
void newConnection(int socketDescriptor);
};
#endif // QMULTITCPSERVER_H
代码语言:javascript复制
#include "qmultitcpserver.h"
QMultiTcpServer::QMultiTcpServer(QObject* parent):QTcpServer(parent)
{ 

}
QMultiTcpServer::~QMultiTcpServer()
{ 

}
void QMultiTcpServer::incomingConnection(int socketDescriptor)
{ 

emit this->newConnection(socketDescriptor);
}
bool QMultiTcpServer::listen(const QHostAddress &address, quint16 port)
{ 

return QTcpServer::listen(address, port);
}

示例代码中,我又新增了一个带参数的newConnected信号,目的是为了把socketDescriptor通过信号发射到槽函数中。

然后在主窗体实例化对象:

代码语言:javascript复制
    tcpServer = new QMultiTcpServer(this);
QObject::connect(tcpServer, SIGNAL(newConnection(int)), this, SLOT(slotNewConnected(int)));

对应的槽函数如下:

代码语言:javascript复制
void Widget::slotNewConnected(int socketDescriptor)
{ 

QTcpSocket* socket = new QTcpSocket(this);
if(!socket->setSocketDescriptor(socketDescriptor))
{ 

delete socket;
return;
}
//
// 你可以在这里新建一个处理线程,将socketDescriptor传入处理线程,我这里直接是演示怎么使用
//
QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(slotReadyRead()));
QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(slotDisconnected()));
qDebug("[%s:%d]: connected.", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort());
}
void Widget::slotReadyRead()
{ 

QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());  // 取得当前socket对象
QByteArray data = socket->readAll();
qDebug("[%s:%d]:%s", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort(), data.toStdString().c_str());
}
void Widget::slotDisconnected()
{ 

QTcpSocket* socket = qobject_cast<QTcpSocket*>(sender());  // 取得当前socket对象
socket->close();
qDebug("[%s:%d]: disconnected.", socket->peerAddress().toString().toStdString().c_str(), socket->peerPort());
delete socket;
}

~~~~~~~~ 附上多线程tcp服务器的一个demo,代码功能比较简单,就是只有回显功能。客户端接入后新开一个线程处理数据的发送和接收,执行效果如下: https://github.com/wowyyy/QtThreadServer


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/197302.html原文链接:https://javaforall.cn

0 人点赞