代码 :
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 ))); }