QT TCP通信

QT TCP功能实现类

QT封装了QTcpSocket 类和QTcpServer类用于实现TCP通信功能可点击QTcpSocket官方说明以及QTcpServer官方说明查看。

二次封装说明

服务器类以及客户端类都封装了sendMsg槽函数用于发送数据以及slotDataRecived槽函数用于接收数据。可根据实际需要对这两个函数进行再次封装。

功能代码

tcpService.h

#pragma once
#include <QObject>
#include <QTcpSocket>
#include <QTcpServer>

#include <unordered_map>
#include <mutex>

class TcpSocket : public QTcpSocket
{
	Q_OBJECT //添加宏以实现信号槽通信机制
public:
	TcpSocket(void);
	~TcpSocket(void) {};
signals:
	/*
	@brife 套接字断开连接信号
	@param descriptor 套接字文件描述符
	*/
	void socketDisconnected(const qintptr& descriptor);

	/*
	@brife 数据接收信号
	@param msg 数据
	*/
	void socketRecived(const QByteArray& msg);

protected slots:
	/*
	@brife 套接字断开连接槽函数
	*/
	void slotSocketDisconnected(void);

	/*
	@brife 数据接收槽函数
	*/
	void slotSocketRecived(void);
};

class TcpService : public QTcpServer
{
	Q_OBJECT //添加宏以实现信号槽通信机制
private:
	//连接的套接字
	std::unordered_map<qintptr, TcpSocket*> mConnectSocket;
	std::mutex mConnectSocketMutex;

public:
	TcpService(const QHostAddress& addr, const int& port);
	~TcpService();

protected slots:
	/*
	@brife 套接字断开连接槽函数
	@param descriptor 套接字文件描述符
	*/
	virtual void slotSocketDisconnected(const qintptr& descriptor);

	/*
	@brife 接收数据槽函数
	*/
	virtual void slotDataRecived(const QByteArray& msg);

protected:
	/*
	@brife 套接字连接回调
	@param socketDescriptor 套接字描述符
	*/
	virtual void incomingConnection(qintptr socketDescriptor) override;

public:
	/*
	@brife 发送数据
	@param msg 数据信息
	@param len 数长度
	*/
	void sendMsg(const char* msg, const qint64& len);
};

tcpService.cpp

#include "tcpService.h"

#include <QDebug>

TcpSocket::TcpSocket(void)
{
	connect(this, &QTcpSocket::disconnected, this, &TcpSocket::slotSocketDisconnected);
	connect(this, &QTcpSocket::readyRead, this, &TcpSocket::slotSocketRecived);
}

void TcpSocket::slotSocketDisconnected(void)
{
	emit socketDisconnected(this->socketDescriptor());
}

void TcpSocket::slotSocketRecived(void)
{
	while (0 < this->bytesAvailable())
	{
		QByteArray msg = this->readAll();
		emit socketRecived(msg);
	}
}

TcpService::TcpService(const QHostAddress& addr, const int& port)
{
	listen(addr, port);
}

TcpService::~TcpService()
{
	{
		std::lock_guard<std::mutex> lck(mConnectSocketMutex);
		for (auto& it : mConnectSocket)
		{
			delete it.second;
		}
	}
}

void TcpService::slotSocketDisconnected(const qintptr& descriptor)
{
	std::lock_guard<std::mutex> lck(mConnectSocketMutex);
	auto it = mConnectSocket.find(descriptor);
	if (mConnectSocket.end() != it)
	{
		delete it->second;
		mConnectSocket.erase(descriptor);
	}
}

void TcpService::slotDataRecived(const QByteArray& msg)
{
	QString data = QString::fromUtf8(msg);
	qDebug() << "service recv:" << data.toStdString().c_str();
}

void TcpService::incomingConnection(qintptr socketDescriptor)
{
	TcpSocket* mTcpSocket = new TcpSocket;
	connect(mTcpSocket, &TcpSocket::socketDisconnected, this, &TcpService::slotSocketDisconnected);
	connect(mTcpSocket, &TcpSocket::socketRecived, this, &TcpService::slotDataRecived);
	mTcpSocket->setSocketDescriptor(socketDescriptor);
	{
		std::lock_guard<std::mutex> lck(mConnectSocketMutex);
		mConnectSocket[socketDescriptor] = mTcpSocket;
	}
}

void TcpService::sendMsg(const char* msg, const qint64& len)
{
	qint64 sendLen = 0;
	std::lock_guard<std::mutex> lck(mConnectSocketMutex);
	for (auto& it : mConnectSocket)
	{
		if (len != (sendLen = it.second->write(msg, len)))
		{
			qDebug() << "msg len:" << len << "\tsend len:" << sendLen << "\tsend failed!!";
		}
	}
}

tcpClient.h

#pragma once
#include <qtcpsocket.h>
#include <QHostAddress>
#include <QTcpSocket>
#include <QObject>

class TcpClient : public QTcpSocket
{
	Q_OBJECT
public:
	TcpClient(const QHostAddress& addr, const int& port);
	virtual ~TcpClient(void) {};

protected slots:
	virtual void slotConnected(void);
	virtual void slotDisconnected(void);
	virtual void slotDataReceived(void);

public:
	/*
	@brife 发送数据
	@param data 发送的数据
	@param len 数据长度
	*/
	virtual const bool sendMsg(const char* data, const uint32_t& len);
};

tcpClient.cpp

#include "tcpClient.h"

#include <QDebug>
#include <QByteArray>
#include <QString>

TcpClient::TcpClient(const QHostAddress& addr, const int& port)
{
	connect(this, &QTcpSocket::connected, this, &TcpClient::slotConnected);
	connect(this, &QTcpSocket::disconnected, this, &TcpClient::slotDisconnected);
	connect(this, &QTcpSocket::readyRead, this, &TcpClient::slotDataReceived);

	//连接服务器
	this->connectToHost(addr, port);
}

void TcpClient::slotConnected(void)
{
	qDebug() << "client connected!!";
}

void TcpClient::slotDisconnected(void)
{
	qDebug() << "client disconnected!!";
}

void TcpClient::slotDataReceived(void)
{
	if (0 < this->bytesAvailable())
	{
		QByteArray data;
		data.resize(this->bytesAvailable());
		this->read(data.data(), data.size());
		QString msg = data.data();
		qDebug() << "client recv:" << msg.toStdString().c_str();
	}
}

const bool TcpClient::sendMsg(const char* data, const uint32_t& len)
{
	return len == this->write(data, len);
}

main.cpp

#include <QtCore/QCoreApplication>
#include <QDebug>
#include <QTimer>
#include <QObject>

#include "QThread"
#include "tcpclient.h"
#include "tcpService.h"

namespace
{
//IP地址
#define HOST_ADDR QHostAddress::LocalHost
//端口
#define HOST_PORT 6666

class MyTcpService : public QTimer
{
private:
    TcpService* mTcpService;
public:
    MyTcpService(const QHostAddress& addr, const int& port)
    {
        mTcpService = new TcpService(addr, port);
        connect(this, &QTimer::timeout, this, &MyTcpService::solveTimeout);
    }

protected slots:
    void solveTimeout(void)
    {
        QString msg("service msg");
        mTcpService->sendMsg(msg.toStdString().c_str(), msg.size());
    }
};
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    //创建服务端
    MyTcpService mTcpService(HOST_ADDR, HOST_PORT);
    mTcpService.start(500);

    //创建客户端
    TcpClient mTcpClient(HOST_ADDR, HOST_PORT);
    QString msg("client msg");
    mTcpClient.sendMsg(msg.toStdString().c_str(), msg.size());

    return a.exec();
}

执行结果

代码执行后,启动定时器向客户端发送数据,执行结果如下:
在这里插入图片描述

工程源码

源码环境使用VS2019+QT5.14开发,如果不能直接运行,可拷贝相关代码至正常环境运行。可点击工程源码链接获取工程源码。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值