有了线程池,我们下一步就利用 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();
}
}
}
下一次,我会介绍最后的实现功能。