qt tcpsocket_qt中udp通信

qt tcpsocket_qt中udp通信设想有如下场景:若干的客户端与服务器端建立连接,建立连接后,服务器端随机发送字符串给客户端,客户端打印输出。该节案例使用TCP编程。服务器端-单线程头文件#pragmaonce////////////////////////////////////////////////////////////////////////////tcp服务端-单线程处理客户端连接#include&lt…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全系列IDE使用 1年只要46元 售后保障 童叟无欺

设想有如下场景:若干的客户端与服务器端建立连接,建立连接后,服务器端随机发送字符串给客户端,客户端打印输出。该节案例使用TCP编程。

服务器端-单线程

头文件

#pragma once
//
//tcp服务端-单线程处理客户端连接
#include <QAbstractSocket>
#include <QObject>

class QTcpServer;
class SimpleTcpSocketServerDemo : public QObject
{ 
   
	Q_OBJECT

public:
	SimpleTcpSocketServerDemo();

private slots:
	void sendData();
	void displayError(QAbstractSocket::SocketError socketError);

private:
	QStringList m_oData;
	QTcpServer *m_pTcpServer;
};

void testSimpleTcpSocketServerDemo();

源文件

#include "SimpleTcpSocketServerDemo.h"
#include <assert.h>
#include <QTcpServer>
#include <QTcpSocket>
#include <QDebug>
#include <QDataStream>

SimpleTcpSocketServerDemo::SimpleTcpSocketServerDemo()
{ 
   
	//初始换原始数据
	m_oData << tr("You've been leading a dog's life. Stay off the furniture.")
					<< tr("You've got to think about tomorrow.")
					<< tr("You will be surprised by a loud noise.")
					<< tr("You will feel hungry again in another hour.")
					<< tr("You might have mail.")
					<< tr("You cannot kill time without injuring eternity.")
					<< tr("Computers are not intelligent. They only think they are.");

	//1. 创建TCP对象
	m_pTcpServer = new QTcpServer(this);
	//2. 新连接、错误信号
	connect(m_pTcpServer, &QTcpServer::newConnection, this, &SimpleTcpSocketServerDemo::sendData);
	connect(m_pTcpServer, &QTcpServer::acceptError, this, &SimpleTcpSocketServerDemo::displayError);
	//3. 启动服务端
	if (!m_pTcpServer->listen(QHostAddress::Any, 8888))
	{ 
   
		qDebug() << "m_pTcpServer->listen() error";
		assert(false);
	}
}

void SimpleTcpSocketServerDemo::sendData()
{ 
   
	//获取服务端数据
	QString sWriteData = m_oData.at(qrand() % m_oData.size());
	//获取与客户端通信的socket
	QTcpSocket* pClientConnection = m_pTcpServer->nextPendingConnection();
	//从客户端读数据
	QString sReadData = pClientConnection->readAll();
	qDebug() << "SimpleTcpSocketServerDemo::readDataFromClient " << pClientConnection;
	//与客户端写数据
	qDebug() << "SimpleTcpSocketServerDemo::writeDataToClient " << sWriteData;
	pClientConnection->write(sWriteData.toUtf8());
// //与客户端断开连接
// connect(pClientConnection, &QTcpSocket::disconnected, this, &SimpleTcpSocketServerDemo::deleteLater);
// pClientConnection->disconnectFromHost();
}

void SimpleTcpSocketServerDemo::displayError(QAbstractSocket::SocketError socketError)
{ 
   
	qDebug() << "SimpleTcpSocketServerDemo::displayError " << socketError;
}

void testSimpleTcpSocketServerDemo()
{ 
   
    //这样写会内存泄漏,如此写方便测试。
	SimpleTcpSocketServerDemo* pSimpleTcpSocketServer = new SimpleTcpSocketServerDemo;
}

客户端

头文件

#pragma once
//
//客户端
#include <QObject>
#include <QAbstractSocket>
#include <QRunnable>
#include <QThreadPool>

class QTcpSocket;
class SimpleTcpSocketClientDemo : public QObject
{ 
   
	Q_OBJECT

public:
	SimpleTcpSocketClientDemo();

private slots:
	void connected();
	void readyRead();
	void error(QAbstractSocket::SocketError socketError);

private:
	QTcpSocket* m_pTcpSocket;
};

class ClientRunnable : public QRunnable
{ 
   
public:
	void run();
};

void testSimpleTcpSocketClientDemo();

源文件

#include "SimpleTcpSocketClientDemo.h"
#include <QTcpSocket>
#include <QDebug>

SimpleTcpSocketClientDemo::SimpleTcpSocketClientDemo()
{ 
   
	//1. 创建TCP套接字对象
	m_pTcpSocket = new QTcpSocket(this);
	//2. 已连接、数据可读、失败信号连接
	connect(m_pTcpSocket, &QTcpSocket::connected, this, &SimpleTcpSocketClientDemo::connected);
	connect(m_pTcpSocket, &QIODevice::readyRead, this, &SimpleTcpSocketClientDemo::readyRead);
	typedef void (QAbstractSocket::*QAbstractSocketErrorSignal)(QAbstractSocket::SocketError);
	connect(m_pTcpSocket, static_cast<QAbstractSocketErrorSignal>(&QTcpSocket::error), this, &SimpleTcpSocketClientDemo::error);
	//3. 与服务器端建立连接
	m_pTcpSocket->connectToHost("127.0.0.1", 8888);
	//4. 同步处理-等待数据可读
	m_pTcpSocket->waitForReadyRead();
}

void SimpleTcpSocketClientDemo::readyRead()
{ 
   
	qDebug() << "SimpleTcpSocketClientDemo::readyRead " << m_pTcpSocket->readAll();
}

void SimpleTcpSocketClientDemo::connected()
{ 
   
	qDebug() << "SimpleTcpSocketClientDemo::connected successfully";
}

void SimpleTcpSocketClientDemo::error(QAbstractSocket::SocketError socketError)
{ 
   
	qDebug() << "SimpleTcpSocketClientDemo::error " << socketError;
}

void ClientRunnable::run()
{ 
   
    //这样写会内存泄漏,如此写方便测试。
	SimpleTcpSocketClientDemo* pSimpleTcpSocketClient = new SimpleTcpSocketClientDemo;
}

#define CLINET_COUNT 2000 //客户端的数量
void testSimpleTcpSocketClientDemo()
{ 
   
	QTime oTime;
	oTime.start();
	
    //同步线程池的方式模拟多个客户端与服务器端交互
	for (int nIndex = 0; nIndex < CLINET_COUNT; ++nIndex)
	{ 
   
		ClientRunnable* pRunnable = new ClientRunnable;
		pRunnable->setAutoDelete(false);
		QThreadPool::globalInstance()->start(pRunnable);
	}
	
	QThreadPool::globalInstance()->waitForDone(30 * 1000);
	qDebug() << "connect count: " << CLINET_COUNT << "total time: " << (double)oTime.elapsed() / double(1000) << "s";
}

测试结果-单线程

服务器端

SimpleTcpSocketServerDemo::readDataFromClient  QTcpSocket(0x2f27f308)
SimpleTcpSocketServerDemo::writeDataToClient  "You will feel hungry again in another hour."
SimpleTcpSocketServerDemo::readDataFromClient  QTcpSocket(0x2eb61cf0)
SimpleTcpSocketServerDemo::writeDataToClient  "You might have mail."
.........

客户端

SimpleTcpSocketClientDemo::connected  successfully
SimpleTcpSocketClientDemo::readyRead  "You might have mail."
SimpleTcpSocketClientDemo::connected  successfully
SimpleTcpSocketClientDemo::readyRead  "You will feel hungry again in another hour."
.........
connect count:  2000 total time:  3.926 s

通过测试输出,可以看到服务器端与客户端建立了正确的连接并且数据交换。

– 实际测试数据:2000个连接,耗时4s左右,CPU使用率10%左右。

通过阅读服务器端,发现单线程处理客户端的连接效率较低。服务器端可修改为多线程处理客户端连接,代码如下:

服务器端-多线程

头文件

#pragma once
//
//服务器端-多线程处理客户端连接

#include <QTcpServer>
#include <QThread>
class MultiThreadTcpSocketServerDemo : public QTcpServer
{ 
   
public:
	MultiThreadTcpSocketServerDemo();
	//This virtual function is called by QTcpServer when a new connection is available. 
	//The socketDescriptor argument is the native socket descriptor for the accepted connection.
	virtual void incomingConnection(qintptr handle);

private:
	QStringList m_oData;
};

//处理线程
class ServerHandleThread : public QThread
{ 
   
	Q_OBJECT

public:
	ServerHandleThread(qintptr handle, const QString& sWriteData);

	virtual void run();
private:
	qintptr m_nHandle;
	QString m_sWriteData;
};

void testMultiThreadTcpSocketServerDemo();

//This virtual function is called by QTcpServer when a new connection is available.
//The socketDescriptor argument is the native socket descriptor for the accepted connection.
virtual void incomingConnection(qintptr handle); //该虚函数是重点

源文件

#include "MultiThreadTcpSocketServerDemo.h"
#include <QDebug>
#include <QTcpSocket>

MultiThreadTcpSocketServerDemo::MultiThreadTcpSocketServerDemo()
{ 
   
	//初始换原始数据
	m_oData << tr("You've been leading a dog's life. Stay off the furniture.")
		<< tr("You've got to think about tomorrow.")
		<< tr("You will be surprised by a loud noise.")
		<< tr("You will feel hungry again in another hour.")
		<< tr("You might have mail.")
		<< tr("You cannot kill time without injuring eternity.")
		<< tr("Computers are not intelligent. They only think they are.");
}

void MultiThreadTcpSocketServerDemo::incomingConnection(qintptr handle)
{ 
   
	//获取服务端数据
	QString sWriteData = m_oData.at(qrand() % m_oData.size());
	qDebug() << "MultiThreadTcpSocketServerDemo::incomingConnection" << handle;
	ServerHandleThread* pThread = new ServerHandleThread(handle, sWriteData);
	connect(pThread, &ServerHandleThread::finished, pThread, &ServerHandleThread::deleteLater);
	pThread->start();
}

ServerHandleThread::ServerHandleThread(qintptr handle, const QString& sWriteData)
:m_sWriteData(sWriteData), m_nHandle(handle)
{ 
   

}

void ServerHandleThread::run()
{ 
   
	//1. 建立与客户端通信的TCP套接字
	QTcpSocket oTcpSocket;
	if (!oTcpSocket.setSocketDescriptor(m_nHandle))
	{ 
   
		qDebug() << "oTcpSocket.setSocketDescriptor error";
		return;
	}

	//2. 向客户端写数据
	qDebug() << "MultiThreadTcpSocketServerDemo::readDataFromClient" << &oTcpSocket;
	qDebug() << "MultiThreadTcpSocketServerDemo::writeDataToClient" << m_sWriteData;
	oTcpSocket.write(m_sWriteData.toUtf8());
	oTcpSocket.disconnectFromHost();
	oTcpSocket.waitForDisconnected();
}

void testMultiThreadTcpSocketServerDemo()
{ 
   
	//1. 建立服务器端套接字
	MultiThreadTcpSocketServerDemo* m_pTcpServer = new MultiThreadTcpSocketServerDemo();
	//2. 启动服务端
	if (!m_pTcpServer->listen(QHostAddress::Any, 8888))
	{ 
   
		qDebug() << "m_pTcpServer->listen() error";
	}
}

测试结果-多线程

客户端

SimpleTcpSocketClientDemo::connected  successfully
SimpleTcpSocketClientDemo::readyRead  "You might have mail."
SimpleTcpSocketClientDemo::connected  successfully
SimpleTcpSocketClientDemo::readyRead  "You will feel hungry again in another hour."
.........
connect count:  2000 total time:  6.403 s

– 实际测试数据:2000个连接,耗时6.5s左右,CPU使用率20%左右。

可见服务器端采用多线程可充分利用CPU,但是频繁的切换线程也会性能下降(耗时)。

通过本案例的代码实现可以了解TCP服务器端/客户端编程的基本思路。并且验证了服务器端单线程和多线程的效率对比。
在windows中,可通过IOCP提高服务期端的效率,后面会详细讲解。

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 8000401a错误解决方案(Word应用程序无法访问)

    8000401a错误解决方案(Word应用程序无法访问)前一阵子做开发需要用到Excel和Word编程,本人用的是Vista系统,开发环境是VS2005和Office2007,测试无任何问题,可是到部署的时候出现了一些令人很头痛的问题,老是会出现例如:检索COM类工厂中CLSID为{000209FF-0000-0000-C000-000000000046}的组件时失败,原因是出现以下错误:8000401a。的错误,在网上查询了许多资

    2022年7月25日
    17
  • AdventureWorks2008R2安装过程可能会遇到的一些问题及解决方案

    AdventureWorks2008R2安装过程可能会遇到的一些问题及解决方案AdventureWorks2008R2范例数据库对于学习SQLServer2008R2是一个非常好的学习案例库,里面包含了一些详尽的数据库案例(官网下载)。但是如果直接安装的话,可能会遇到一些问题,下面介绍安装的一些必要前提:1.安装的数据库账户应具有系统权限。2.你所安装的数据库至少是”SQLServerExpresswithAdvancedServices“版本(我所安…

    2022年9月11日
    1
  • js算法初窥01(排序算法01-冒泡、选择、插入)

    排序,我想大家一定经历过或者正在经历着。或许你不懂算法,对排序算法一无所知,但是你一定用过一些第三方库的api来一键排序,那么,在你享受便捷的同时,你是否想过它的底层是如何实现的?这样的算法实现方式是

    2022年3月25日
    34
  • Xshell出现要继续使用此程序必须应用到最新的更新或使用新版本

    Xshell出现要继续使用此程序必须应用到最新的更新或使用新版本

    2021年11月4日
    81
  • ringbuffer原理_hashset数据结构

    ringbuffer原理_hashset数据结构本篇介绍一种简单高效的数据缓存结构:RingBuffer,这种结构实现起来只需要几行代码即可,但使用场景却很广泛,比如在Linux内核中网络数据包的缓存,系统日志的存储等多处使用过该结构。同时它也被广泛的应用于异步通信以及嵌入式设备中,提供高效的数据缓存读写操作。1.实现原理RingBufferr实现比较简单,基本上只需要一个数组结构,外加两个用于存储位置信息的变量即可。其中的数组采用固定大小容量,便于重用内存,不会出现动态内存不断分配和销毁的情况,这对于一些GC类编程语言来说,大…

    2022年9月10日
    2
  • 融合计费账务系统架构与核心功能的研究与实现

    融合计费账务系统架构与核心功能的研究与实现2006年初,融合计费账务系统的发展趋势及其重要性已得到业界的广泛关注,各电信运营商及开发商也开始了相应的讨论、研究和规划,北京联通(原北京网通)在业务和网络的发展驱动下,率先开始了融合计费账务系统的规划与建设,真正建设一个统一支撑大客户、商务客户和公众客户所有客户群,统一支撑北京联通电话、宽带、小灵通、互联网、专线及CP/SP业务等全业务及其灵活捆绑与组合营销,统一支撑在线…

    2025年6月17日
    2

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号