QTcpSocket和QTcpServer的理解和使用

TCP 协议是一种面向连接的、可靠的、基于字节流的传输层通信协议,通过三次握手来建立可靠的连接。

在这里插入图片描述

TCP连接是双向的,断开时经历四次挥手,在四次挥手中,前两次挥手用于断开一个方向的连接,后两次挥手用于断开另一方向的连接。

在这里插入图片描述

QTcpSocket 继承自QAbstractSocket 类,用于建立 TCP 连接并传输数据流。
QTcpServer 服务端通过 nextPendingConnection() 接口获取到建立了 TCP 连接的 QTcpSocket 对象。
客户端在创建好 QTcpSocket 对象后,调用 connectToHost() 连接到服务端

服务端代码如下:

.h
class ServerProject : public QWidget
{
    Q_OBJECT
public:
    ServerProject(QWidget *parent = nullptr);
    ~ServerProject();
    void iniServer();
    void closeServer();
private slots:
    void on_listenBtn_clicked();
    void on_sendBtn_clicked();
    void newConnectionSlot();
    void readyReadSlot();
private:
    Ui::ServerProjectClass ui;
	QTcpServer* m_server;
    QTcpSocket* m_socket;
};
.cpp
ServerProject::ServerProject(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    setWindowTitle("Server");
    iniServer();
}
ServerProject::~ServerProject()
{
	closeServer();
	if (m_socket != NULL) {
		delete m_socket;
		m_socket = NULL;
	}
}
void ServerProject::iniServer() {
	m_socket = NULL;
    m_server = new QTcpServer(this);
}
void ServerProject::closeServer() {
	m_server->close();
	if (m_socket == NULL) {
		return;
	}
	//断开与客户端的连接
	if (m_socket->state() == QAbstractSocket::ConnectedState) {
		m_socket->disconnectFromHost();
		if (m_socket->state() != QAbstractSocket::UnconnectedState) {
			m_socket->abort();
		}
	}
}
void ServerProject::on_listenBtn_clicked() {
	if (m_server->isListening()) {
		closeServer();
		//关闭server后恢复界面状态
		ui.listenBtn->setText("Listen");
		ui.addressEt->setEnabled(true);
		ui.portEt->setEnabled(true);
	}
	else {
		//可以使用 QHostAddress::Any 监听所有地址的对应端口
		const QString address_text = ui.addressEt->text();
		const unsigned short port = ui.portEt->text().toUShort();
		const QHostAddress address = (address_text == "Any")
			? QHostAddress::Any
			: QHostAddress(address_text);
		//开始监听,并判断是否成功
		if (m_server->listen(address, port)) {
			//连接成功就修改界面按钮提示,以及地址栏不可编辑
			ui.listenBtn->setText("Close");
			ui.addressEt->setEnabled(false);
			ui.portEt->setEnabled(false);
		}
		connect(m_server, &QTcpServer::newConnection, this, &ServerProject::newConnectionSlot);
	}
}
void ServerProject::newConnectionSlot() {
	if (m_server->hasPendingConnections())
	{
		//nextPendingConnection返回下一个挂起的连接作为已连接的QTcpSocket对象
		//套接字是作为服务器的子级创建的,这意味着销毁QTcpServer对象时会自动删除该套接字。
		//最好在完成处理后显式删除该对象,以避免浪费内存。
		//返回的QTcpSocket对象不能从另一个线程使用,如有需要可重写incomingConnection().
		m_socket = m_server->nextPendingConnection();
		ui.receiveEt->append("connected.........");
		connect(m_socket, &QTcpSocket::readyRead, this, &ServerProject::readyReadSlot);
	}
}
void ServerProject::readyReadSlot() {
	if (m_socket->bytesAvailable() <= 0)
		return;
	//注意收发两端文本要使用对应的编解码
	const QString recv_text = QString::fromUtf8(m_socket->readAll());
	ui.receiveEt->append(recv_text);
}

void ServerProject::on_sendBtn_clicked() {
	if (!m_server->isListening())
		return;
	//将发送区文本发送给客户端
	const QByteArray send_data = ui.sendEt->toPlainText().toUtf8();
	//数据为空就返回
	if (send_data.isEmpty())
		return;
	m_socket->write(send_data);
}

客户端代码如下:

.h
class ClientPro : public QWidget
{
    Q_OBJECT
public:
    ClientPro(QWidget *parent = nullptr);
    ~ClientPro();
	//初始化client操作
	void initClient();
private slots:
    void on_connectBtn_clicked();
    void on_sendBtn_clicked();
    void connectedSlot();
    void disconnectedSlot();
    void readyReadSlot();
private:
    Ui::ClientProClass ui;
    QTcpSocket* m_client;
};
.cpp
ClientPro::ClientPro(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    initClient();
}
ClientPro::~ClientPro()
{
	qDebug() << "~ClientPro()----------------------------";
	if (m_client->state() == QAbstractSocket::ConnectedState) {
		//如果使用disconnectFromHost()不会重置套接字,isValid还是会为true
		m_client->abort();
	}
}
void ClientPro::initClient() {
	//创建client对象
	m_client = new QTcpSocket(this);
}
void ClientPro::on_connectBtn_clicked() {
	if (m_client->state() == QAbstractSocket::ConnectedState) {
		//如果使用disconnectFromHost()不会重置套接字,isValid还是会为true
		m_client->abort();
	}
	else if (m_client->state() == QAbstractSocket::UnconnectedState) {
		//从界面上读取ip和端口
		const QHostAddress address = QHostAddress(ui.addressEt->text());
		const unsigned short port = ui.portEt->text().toUShort();
		//连接服务器
		m_client->connectToHost(address, port);
	}
	else {
		ui.receiveEt->append("It is not ConnectedState or UnconnectedState");
	}
	connect(m_client, &QTcpSocket::connected, this, &ClientPro::connectedSlot);
	connect(m_client, &QTcpSocket::disconnected, this, &ClientPro::disconnectedSlot);
	connect(m_client, &QTcpSocket::readyRead, this, &ClientPro::readyReadSlot);
}
void ClientPro::connectedSlot() {
	ui.connectBtn->setText("Disconnect");
	ui.addressEt->setEnabled(false);
	ui.portEt->setEnabled(false);
}
void ClientPro::disconnectedSlot() {
	ui.connectBtn->setText("Connect");
	ui.addressEt->setEnabled(true);
	ui.portEt->setEnabled(true);
}
void ClientPro::readyReadSlot() {
	if (m_client->bytesAvailable() <= 0)
		return;
	//注意收发两端文本要使用对应的编解码
	const QString recv_text = QString::fromUtf8(m_client->readAll());
	ui.receiveEt->append(recv_text);
}
void ClientPro::on_sendBtn_clicked() {
	if (!m_client->isValid())
		return;
	//将发送区文本发送给客户端
	const QByteArray send_data = ui.sendEt->toPlainText().toUtf8();
	//数据为空就返回
	if (send_data.isEmpty())
		return;
	m_client->write(send_data);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
incomingConnection() 函数是在 QTcpServer 类中的一个虚函数,它在有新的客户端连接到服务器时被调用。incomingConnection() 的主要作用是接受新的连接并创建一个新的 QTcpSocket 对象来处理该连接。 在使用 QTcpServer 创建一个 TCP 服务器时,我们需要先调用 listen() 函数来监听客户端的连接。当有客户端连接到服务器时,QTcpServer 会接受该连接并在一个新的线程中调用 incomingConnection() 函数。在 incomingConnection() 函数中,我们可以使用 nextPendingConnection() 函数获取一个新的 QTcpSocket 对象,然后可以对这个 QTcpSocket 对象进行操作,例如读取客户端发送的数据、向客户端发送数据、断开连接等。 下面是一个 incomingConnection() 函数的示例: ```cpp void MyServer::incomingConnection(qintptr socketDescriptor) { QTcpSocket *socket = new QTcpSocket(this); socket->setSocketDescriptor(socketDescriptor); // 处理新的连接 // ... // 断开连接 socket->disconnectFromHost(); } ``` 在 incomingConnection() 函数中,我们创建了一个新的 QTcpSocket 对象,并使用 setSocketDescriptor() 函数将其与客户端的套接字描述符关联起来。然后,我们可以对这个 QTcpSocket 对象进行操作,例如读取客户端发送的数据、向客户端发送数据、断开连接等。最后,我们使用 disconnectFromHost() 函数将 QTcpSocket 对象与客户端断开连接。 需要注意的是,在 incomingConnection() 函数中创建的 QTcpSocket 对象需要手动管理内存,即需要在不需要使用它时删除它。另外,incomingConnection() 函数是在一个新的线程中被调用的,因此需要注意线程安全问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值