qt tcpserver linux,实现通信功能 - QT 线程池 + TCP 实战笔记_Linux编程_Linux公社-Linux系统门户网站...

本文介绍了如何使用QTcpServer创建服务器,处理客户端连接,并结合线程池处理数据。当客户端断开时,仍可能处理剩余任务,除非通过信号删除。文章还提到,QTcpSocket支持大体积数据发送,外层实现发送队列以控制数据包大小。此外,提供了包括接收新连接、数据读取、错误处理等在内的服务器关键功能的详细实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有了线程池,我们下一步就利用 QTcpServer 搭建一个服务器,接受客户端的连接,并把数据发送到线程池上。由于 QTcpServer 资料太多了,这里不在赘述。唯一值得注意的是,当客户端退出时,如果线程池队列中还有该客户的信息,这个信息还会被处理,只是无法再发送回去而已。其实,还可实现成客户端退出,就发一个信号到线程池,删除自己的所有任务。这个也很简单,但之所以没有做,因为这些数据的处理结果可能还会被其他消费者(而非生产者自己)使用,最典型的例子是从工业传感器上采集的数据,其生成的图像需要存储到设备中去。

QTcpSocket的 Write 方法默认是支持大体积数据的,即使一次发了500MB的数据,只要硬件资源可以承受,调用也会成功并立刻返回。接受者会以一定的载荷大小不停的触发readyRead,直到发送全部成功。但是,为了能够观察到并控制收发队列中的数据包的大小、体积,我们在外层实现了一个发送队列,每次以 payLoad为大小发送数据包。这是从MFC中带来的习惯,很难说好坏。

qghtcpserver.h

#ifndef QGHTCPSERVER_H

#define QGHTCPSERVER_H

#include 

#include 

#include 

classQGHTcpServer :publicQTcpServer

{

Q_OBJECT

public:

QGHTcpServer(QObject *parent,intnPayLoad = 4096);

~QGHTcpServer();

//踢出所有客户

voidKickAllClients();

QList  clientsList();

voidSetPayload(intnPayload);

private:

QMap > m_buffer_sending;

QMap > m_buffer_sending_offset;

QMap m_clientList;

intm_nPayLoad;

publicslots:

//新的客户连接到来

voidnew_client_recieved();

//客户连接被关闭

voidclient_closed();

//新的数据到来

voidnew_data_recieved();

//一批数据发送完毕

voidsome_data_sended(qint64);

//客户端错误

voiddisplayError(QAbstractSocket::SocketError socketError);

//向客户端发送数据

voidSendDataToClient(QObject * objClient,constQByteArray &  dtarray);

//向客户端广播数据,不包括 objFromClient

voidBroadcastData(QObject * objFromClient,constQByteArray &  dtarray);

signals:

//错误信息

voidevt_SocketError(QObject * senderSock ,QAbstractSocket::SocketError socketError);

//新的客户端连接

voidevt_NewClientConnected(QObject * client);

//客户端退出

voidevt_ClientDisconnected(QObject * client);

//收到一批数据

voidevt_Data_recieved(QObject * ,constQByteArray &  );

//一批数据被发送

voidevt_Data_transferred(QObject * client,qint64);

};

#endif // QGHTCPSERVER_H

qghtcpserver.cpp

#include "qghtcpserver.h"

#include 

#include 

QGHTcpServer::QGHTcpServer(QObject *parent,intnPayLoad )

: QTcpServer(parent),

m_nPayLoad(nPayLoad)

{

assert(m_nPayLoad>=256 && m_nPayLoad<=16*1024*1024);

connect(this, SIGNAL(newConnection()),this, SLOT(new_client_recieved()));

}

QGHTcpServer::~QGHTcpServer()

{

}

QList  QGHTcpServer::clientsList()

{

returnm_clientList.keys();

}

voidQGHTcpServer::SetPayload(intnPayload)

{

m_nPayLoad = nPayload;

assert(m_nPayLoad>=256 && m_nPayLoad<=16*1024*1024);

}

voidQGHTcpServer::new_client_recieved()

{

QTcpSocket * sock_client = nextPendingConnection();

while(sock_client)

{

connect(sock_client, SIGNAL(readyRead()),this, SLOT(new_data_recieved()));

connect(sock_client, SIGNAL(disconnected()),this,SLOT(client_closed()));

connect(sock_client, SIGNAL(error(QAbstractSocket::SocketError)),this, SLOT(displayError(QAbstractSocket::SocketError)));

connect(sock_client, SIGNAL(bytesWritten(qint64)),this, SLOT(some_data_sended(qint64)));

m_clientList[sock_client] = 0;

emit evt_NewClientConnected(sock_client);

sock_client = nextPendingConnection();

}

}

voidQGHTcpServer::client_closed()

{

QTcpSocket * pSock = qobject_cast(sender());

if(pSock)

{

emit evt_ClientDisconnected(pSock);

m_buffer_sending.remove(pSock);

m_buffer_sending_offset.remove(pSock);

m_clientList.remove(pSock);

pSock->deleteLater();

}

}

voidQGHTcpServer::new_data_recieved()

{

QTcpSocket * pSock = qobject_cast(sender());

if(pSock)

emit evt_Data_recieved(pSock,pSock->readAll());

}

voidQGHTcpServer::some_data_sended(qint64 wsended)

{

QTcpSocket * pSock = qobject_cast(sender());

if(pSock)

{

emit evt_Data_transferred(pSock,wsended);

QList & list_sock_data = m_buffer_sending[pSock];

QList & list_offset = m_buffer_sending_offset[pSock];

while(list_sock_data.empty()==false)

{

QByteArray & arraySending = *list_sock_data.begin();

qint64 & currentOffset = *list_offset.begin();

qint64 nTotalBytes = arraySending.size();

assert(nTotalBytes>=currentOffset);

qint64 nBytesWritten = pSock->write(arraySending.constData()+currentOffset,qMin((int)(nTotalBytes-currentOffset),m_nPayLoad));

currentOffset += nBytesWritten;

if(currentOffset>=nTotalBytes)

{

list_offset.pop_front();

list_sock_data.pop_front();

}

else

break;

}

}

}

voidQGHTcpServer::displayError(QAbstractSocket::SocketError socketError)

{

QTcpSocket * pSock = qobject_cast(sender());

if(pSock)

{

emit evt_SocketError(pSock,socketError);

pSock->disconnectFromHost();

}

}

voidQGHTcpServer::SendDataToClient(QObject * objClient,constQByteArray &  dtarray)

{

if(m_clientList.find(objClient)==m_clientList.end())

return;

QTcpSocket * pSock = qobject_cast(objClient);

if(pSock&&dtarray.size())

{

QList & list_sock_data = m_buffer_sending[pSock];

QList & list_offset = m_buffer_sending_offset[pSock];

if(list_sock_data.empty()==true)

{

qint64 bytesWritten = pSock->write(dtarray.constData(),qMin(dtarray.size(),m_nPayLoad));

if(bytesWritten 

{

list_sock_data.push_back(dtarray);

list_offset.push_back(bytesWritten);

}

}

else

{

list_sock_data.push_back(dtarray);

list_offset.push_back(0);

}

}

}

voidQGHTcpServer::BroadcastData(QObject * objClient,constQByteArray &  dtarray)

{

for(QMap::iterator p = m_clientList.begin();p!=m_clientList.end();p++)

{

QTcpSocket * pSock = qobject_cast(p.key());

if(pSock&&dtarray.size()&&pSock!=objClient)

{

QList & list_sock_data = m_buffer_sending[pSock];

QList & list_offset = m_buffer_sending_offset[pSock];

if(list_sock_data.empty()==true)

{

qint64 bytesWritten = pSock->write(dtarray.constData(),qMin(dtarray.size(),m_nPayLoad));

if(bytesWritten 

{

list_sock_data.push_back(dtarray);

list_offset.push_back(bytesWritten);

}

else

{

list_sock_data.push_back(dtarray);

list_offset.push_back(0);

}

}

}

}

}

voidQGHTcpServer::KickAllClients()

{

QList clientList = m_clientList.keys();

foreach(QObject * obj,clientList)

{

QTcpSocket * pSock = qobject_cast(obj);

if(pSock)

{

pSock->disconnectFromHost();

}

}

}

下一次,我会介绍最后的实现功能。0b1331709591d260c1c78e86d0c51c18.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值