【QT-1】QTCP通信

目录

一、一服务端一客户端示例

二、一服务端多客户端示例

三、问题解决


一、一服务端一客户端示例

以下为服务端代码,客户端采用NetAssist网络调试助手调试。

1、**.ui

添加textEdit窗体

 2、**.h文件

#include <QTcpServer>
#include <QTcpSocket>

...
private:
    Ui::MainWindow *ui;
	QTcpServer *tcpServer; //监听套接字
	QTcpSocket *tcpSocket; //通信套接字

3、**.cpp文件

#include <QTcpServer>//监听套接字
#include <QTcpSocket>//通信套接字

...
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

	tcpServer = NULL;
	tcpSocket = NULL;

...

    //TCP通信服务端代码
    //TCP-监听
	tcpServer = new QTcpServer(this);
	tcpSocket = new QTcpSocket(this);
	tcpServer->listen(QHostAddress::Any, 9999);
	//newConnection代表有新的连接
	connect(tcpServer, &QTcpServer::newConnection,
		[=]()
	{
		//取出建立好连接的套接字
		tcpSocket = tcpServer->nextPendingConnection();

		//获取对方的IP和端口
		QString ip = tcpSocket->peerAddress().toString();
		quint16 port = tcpSocket->peerPort();
		QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
		qDebug() << temp << endl;
		ui->textEditRead->setText(temp);//不用settext 这样会覆盖之前的消息
		//接收信息  必须放到连接中的槽函数 不然tcpsocket就是一个野指针
		//connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::ReadData);

		connect(tcpSocket, &QTcpSocket::readyRead, 
			[=]()
		{
			//从通信套接字中取出内容
			QString str = tcpSocket->readAll();
			qDebug() << str << endl;
			//在编辑区域显示
			ui->textEditRead->append("客户端:" + str);//不用settext 这样会覆盖之前的消息
			Sleep(1000);
			if (str == "Volume") {
				QString l = ui->lineEdit_ObjectLength->text().toUtf8();
				QString w = ui->lineEdit_ObjectWidth->text().toUtf8();
				QString h = ui->lineEdit_ObjectHeight->text().toUtf8();
				QString v = ui->lineEdit_ObjectIntegralVolume->text().toUtf8();
				QString data = "Length:" + l + "," + "Width:" + w + "," + "Height:" + h + "," + "Volume:" + v;

				// 定义 { } 对象
				QJsonObject interestObj;
				// 插入元素,对应键值对
				interestObj.insert("Length", l);
				interestObj.insert("Width", w);
				interestObj.insert("Height", h);
				interestObj.insert("Volume", v);

				//tcpSocket->write(data.toUtf8());

				QJsonDocument document = QJsonDocument(interestObj);
				QByteArray array = document.toJson();// 转换成QByteArray
				tcpSocket->write(array);

			}
			
		});
	
	});

4、测试

上述示例存在一个问题,当多客户端连接时,只要有其中一个发送请求,所有客户端都会收到响应数据。 

二、一服务端多客户端示例

服务端代码:

**.h文件

int m_iClientCount;
QList<QTcpSocket*> listClient;

QTcpServer *tcpServer; //监听套接字
QTcpSocket *tcpSocket; //通信套接字

 **.cpp文件

//TCP-监听
tcpServer = new QTcpServer(this);
//tcpSocket = new QTcpSocket(this);
tcpServer->listen(QHostAddress::Any, 9999);

//newConnection代表有新的连接
connect(tcpServer, &QTcpServer::newConnection,
	[=]()
{
	//取出建立好连接的套接字
	tcpSocket = tcpServer->nextPendingConnection();

	listClient.append(tcpSocket);//将生成的socket添加到容器里
	m_iClientCount++;

	//获取对方的IP和端口
	QString ip = tcpSocket->peerAddress().toString();
	quint16 port = tcpSocket->peerPort();
	QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
	qDebug() << temp << endl;
	ui->textEditRead->append(temp);//不用settext 这样会覆盖之前的消息
	//接收信息  必须放到连接中的槽函数 不然tcpsocket就是一个野指针
	//connect(tcpSocket, &QTcpSocket::readyRead, this, &MainWindow::ReadData);

	connect(tcpSocket, &QTcpSocket::readyRead, 
		[=]()
	{

		QByteArray buffer;
		//利用for循环循环列表中的每一个连接进来的客户端,判断是哪一个客户端发的数据
		for (int i = 0; i < listClient.count(); i++)
		{
			tcpSocket = listClient.at(i);
			buffer = tcpSocket->readAll();
			if (buffer.length() != 0)   //如果检测到接收到的数据长度不为0,则代表是这个客户端发送的数据
				ui->textEditRead->append("客户端:" + buffer);//不用settext 这样会覆盖之前的消息


			if (buffer == "Volume") {
				QString l = ui->lineEdit_ObjectLength->text().toUtf8();
				QString w = ui->lineEdit_ObjectWidth->text().toUtf8();
				QString h = ui->lineEdit_ObjectHeight->text().toUtf8();
				QString ev = ui->lineEdit_ObjectExternalVolume->text().toUtf8();
				QString iv = ui->lineEdit_ObjectIntegralVolume->text().toUtf8();

				//QString data = "Length:" + l + "," + "Width:" + w + "," + "Height:" + h + "," + "Volume:" + v;

				// 定义 { } 对象
				QJsonObject interestObj;
				// 插入元素,对应键值对
				interestObj.insert("Length", l);
				interestObj.insert("Width", w);
				interestObj.insert("Height", h);
				interestObj.insert("ExternalVolume", ev);
				interestObj.insert("IntegralVolume", iv);

				//tcpSocket->write(data.toUtf8());
				QJsonDocument document = QJsonDocument(interestObj);
				QByteArray array = document.toJson();// 转换成QByteArray
				tcpSocket->write(array);
			}
		}
	});
});

断开连接槽函数:

connect(tcpSocket_new, &QTcpSocket::disconnected, [=]()
{
	//tcpSocket->disconnectFromHost();//主动和客户端断开连接
	for (int i = 0; i < listClient.count(); i++)
	{
		QTcpSocket* tcpSocket1 = listClient.at(i);
		if (tcpSocket1 == tcpSocket_new)
		{
			qDebug() << tcpSocket_new << "disconnected!";
			listClient.removeOne(tcpSocket_new);
			//删除套接字
			//tcpSocket_new->deleteLater();			
		}
	}
});

连接状态:

if (tcpSocket_new->state() == QAbstractSocket::UnconnectedState)
{
	return;
}

三、问题解决

TCP通信接收数据不全,存在丢包现象,因为网络数据的传输是分包进行的,而readAll()只会读取当前可用的数据,并不保证一次性读取完整。

解决方案:

while (tcpSocket->bytesAvailable() > 0) 
{
	NewDelayTime(2000);
	QByteArray buffer = tcpSocket->readAll();
	bufferall.append(buffer);
	qDebug() << bufferall;
	if (bufferall.startsWith("{") && bufferall.endsWith("}"))
	{						
		//处理bufferall数据					
	}					
}

//延时
void MainWindow::NewDelayTime(DWORD times)
{
	DWORD dwStart = GetTickCount();
	DWORD dwEnd = dwStart;
	do
	{
		MSG msg;
		if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		dwEnd = GetTickCount();
	} while ((dwEnd - dwStart) <= times);
}

 参考链接 Qt下Tcp套接字(socket)通信的整个流程_qt 建立服务端socket-CSDN博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值