代码 :
1 连接成功后每个连接创建一个处理对象 cclientSession,
2 所有cclientSession对象的slot 都在另外一个线程中处理,即处理方式为创建一个线程处理所有客户端连接
3 大文件传输需要自己用协议分片
#ifndef QNETCONTRLSERVER_H
#define QNETCONTRLSERVER_H
#include <QObject>
#include <QTcpServer>
#include <QTcpSocket>
#include <QThread>
#include <QDebug>
//通信模式 [命令id(4byte)+数据长度(4bytes)+数据(n bytes)]
#define CMD_ID_ALLINFO 1
class CClientSession:public QObject
{
Q_OBJECT
public:
CClientSession(QObject* parent = NULL);
~CClientSession();
public slots:
void onNewDescriptor(qintptr desc);
void onSocketErr(QAbstractSocket::SocketError err);
void onReadDataReady();
void onResponse(QByteArray sndData);
//void onWriteDataReady();
signals:
void newDescriptor(qintptr handle);
void cmdPacket(CClientSession* client,int id, QByteArray data);
void cmdResponse(QByteArray sndData);
protected:
void decodePacket();
private:
QTcpSocket* m_tcpClient;
QByteArray m_cmdPacketTemp;
};
class QNetContrlServer : public QTcpServer
{
Q_OBJECT
public:
QNetContrlServer(QObject *parent = NULL);
virtual ~QNetContrlServer();
public slots:
//void onNewConnection(qintptr descriptor);
protected:
virtual void incomingConnection(qintptr handle);
private:
QThread* m_workThread;
};
#include "qnetcontrlserver.h"
#include "mainwindow.h"
CClientSession::CClientSession(QObject* parent):QObject(parent)
{
connect(this,SIGNAL(newDescriptor(qintptr)),this,SLOT(onNewDescriptor(qintptr)));
connect(this,SIGNAL(cmdResponse(QByteArray )),this,SLOT(onResponse(QByteArray)));
}
CClientSession::~CClientSession()
{
}
void CClientSession::onSocketErr(QAbstractSocket::SocketError err)
{
qDebug()<<"onSocketErr: "<<QThread::currentThreadId() << " socket error: "<<err;
m_tcpClient->disconnectFromHost();
}
void CClientSession::onNewDescriptor(qintptr desc)
{
qDebug()<<"onNewDescriptor: "<<QThread::currentThreadId() << "new descriptor: "<<desc;;
m_tcpClient = new QTcpSocket();
if (!m_tcpClient->setSocketDescriptor(desc))
{
return;
}
connect(m_tcpClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(onSocketErr(QAbstractSocket::SocketError)));
connect(m_tcpClient,SIGNAL(disconnected()),m_tcpClient,SLOT(deleteLater()));
connect(m_tcpClient,SIGNAL(readyRead()),this,SLOT(onReadDataReady()));
}
void CClientSession::onReadDataReady()
{
qDebug()<<"onReadDataReady: "<<QThread::currentThreadId();
qint64 bytes = m_tcpClient->bytesAvailable();
if (bytes > 0)
{
QByteArray buffer = m_tcpClient->read(bytes);
qDebug()<<buffer.toHex();
m_cmdPacketTemp.append(buffer);
decodePacket();
}
}
void CClientSession::decodePacket()
{
while(m_cmdPacketTemp.size() >= 8) //允许客户端一次发送多个命令
{
qint32* ptr = (int*)m_cmdPacketTemp.data();
int cmdId = *ptr++;
int cmdSize = *ptr;
if (m_cmdPacketTemp.size() -8 >= cmdSize )
{
QByteArray data ;
data.append(m_cmdPacketTemp.data()+8,cmdSize);
emit cmdPacket(this,cmdId,data);
m_cmdPacketTemp.remove(0,cmdSize+8);
qDebug()<<"command id: "<<cmdId<<" data size: "<<cmdSize <<"data: "<< data.toHex();
}
else
{
break;
}
}
return;
}
void CClientSession::onResponse(QByteArray sndData)
{
if(sndData.size() > 0)
{
qint64 sndSize = m_tcpClient->write(sndData);
if(!m_tcpClient->waitForBytesWritten()) //大文件传输请自定义协议分片传输,以免阻塞线程
{
m_tcpClient->disconnectFromHost();
}
}
//delete sndData;
}
//
//QNetContrlServer
//
QNetContrlServer::QNetContrlServer(QObject *parent)
: QTcpServer(parent)
{
qRegisterMetaType<QAbstractSocket::SocketError>("SocketError");
qRegisterMetaType<qintptr>("qintptr");
m_workThread = new QThread();
connect(m_workThread,SIGNAL(finished()),m_workThread,SLOT(deleteLater()));
m_workThread->start();
if(!listen(QHostAddress::Any,999))
{
}
}
QNetContrlServer::~QNetContrlServer()
{
}
void QNetContrlServer::incomingConnection(qintptr descriptor)
{
qDebug()<<"incomingConnection: "<<QThread::currentThreadId() << "new descriptor: "<<descriptor;
CClientSession* session = new CClientSession();
//connect(session,SIGNAL(newDescriptor(qintptr)),session,SLOT(onNewDescriptor(qintptr)));
session->moveToThread(m_workThread);
emit session->newDescriptor(descriptor);
//session->onNewDescriptor(descriptor);
MainWindow* qMainWin = (MainWindow*)this->parent();
connect(session,SIGNAL(cmdPacket(CClientSession* ,int , QByteArray )),qMainWin,SLOT(onCmdHandle(CClientSession* ,int , QByteArray )));
}