基于Qt,设计了一个tcp server,主要用到:
- QTcpServer
- QTcpSocket
- QThread
UML 类图:
TcpServer构造函数:
TcpServer(QString t_server_name,quint32 t_thread_cout,msgHandle t_func=nullptr,QObject *parent = nullptr);
- t_server_name:服务名字
- t_thread_cout:支持处理socket的子线程个数
- t_func:消息处理函数,其类型如下:
- typedef std::function<void (QByteArray &msg,QTcpSocket* sock)> msgHandle;
TcpServer启动函数:
void startListen(quint16 t_port);
tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include "tcpsocket.h"
#include <QObject>
#include <QTcpServer>
#include <QString>
#include <QThread>
#include <QVector>
struct SocketInfo
{
quint32 socket_num;
QThread socket_thread;
};
class TcpServer : public QTcpServer
{
Q_OBJECT
public:
explicit TcpServer(QString t_server_name,quint32 t_thread_cout,msgHandle t_func=nullptr,QObject *parent = nullptr);
~TcpServer();
QString getServerName();
quint16 getServerPort();
public slots:
void setMsgHandle(msgHandle t_func);
void startListen(quint16 t_port);
void stopListen();
void socketClose(qint32 t_id);
protected:
void incomingConnection(qintptr socketDescriptor);
qint32 getMinSocketThread();
private:
QString m_server_name;
quint16 m_port;
quint32 m_thread_count;
QVector<SocketInfo*> m_thread_vec;
msgHandle m_func;
};
#endif // TCPSERVER_H
tcpserver.cpp
#include "tcpserver.h"
#include <QByteArray>
#include <QHostAddress>
#include <QNetworkProxyFactory>
#include <QDebug>
TcpServer::TcpServer(QString t_server_name,quint32 t_thread_cout,msgHandle t_func,QObject *parent) :
QTcpServer(parent),
m_server_name(t_server_name),
m_thread_count(t_thread_cout),
m_func(t_func)
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"this server is:"<<t_server_name<<endl;
this->m_port=0;
for(quint32 index=0;index<this->m_thread_count;index++)
{
SocketInfo *tmp_info=new SocketInfo();
tmp_info->socket_num=0;
tmp_info->socket_thread.start();
this->m_thread_vec.append(tmp_info);
}
}
TcpServer::~TcpServer()
{
if(this->isListening())
{
this->close();
}
int cout=this->m_thread_vec.size();
for(int index=0;index<cout;index++)
{
this->m_thread_vec[index]->socket_thread.terminate();
this->m_thread_vec[index]->socket_thread.wait();
delete this->m_thread_vec[index];
this->m_thread_vec[index]=nullptr;
}
}
QString TcpServer::getServerName()
{
return this->m_server_name;
}
quint16 TcpServer::getServerPort()
{
return this->m_port;
}
void TcpServer::setMsgHandle(msgHandle t_func)
{
this->m_func=t_func;
}
void TcpServer::startListen(quint16 t_port)
{
if(this->isListening())
{
this->close();
}
if(this->listen(QHostAddress::Any,t_port))
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"listen successful:"<<t_port<<endl;
this->m_port=t_port;
}
else
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"listen failed:"<<t_port<<endl;
}
}
void TcpServer::stopListen()
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"stop listen: "<<this->m_port<<endl;
if(this->isListening())
{
this->close();
}
}
void TcpServer::incomingConnection(qintptr socketDescriptor)
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"new connection: "<<socketDescriptor<<endl;
qint32 cut_id=this->getMinSocketThread();
TcpSocket *tmp_soc=new TcpSocket(cut_id,socketDescriptor,this->m_func);
connect(tmp_soc,SIGNAL(socketClose(qint32)),this,SLOT(socketClose(qint32)));
tmp_soc->moveToThread(&(this->m_thread_vec[cut_id]->socket_thread));
this->m_thread_vec[cut_id]->socket_num++;
}
void TcpServer::socketClose(qint32 t_id)
{
this->m_thread_vec[t_id]->socket_num--;
}
qint32 TcpServer::getMinSocketThread()
{
qint32 tmp_id=0;
qint32 th_cout=this->m_thread_vec.size();
for(qint32 index=0;index<th_cout;index++)
{
if(this->m_thread_vec[index]->socket_num<this->m_thread_vec[tmp_id]->socket_num)
{
tmp_id=index;
}
}
return tmp_id;
}
tcpsocket.h
#ifndef TCPSOCKET_H
#define TCPSOCKET_H
#include <QObject>
#include <QTcpSocket>
#include <QByteArray>
#include <QTimer>
#include <iostream>
#include <functional>
typedef std::function<void (QByteArray &msg,QTcpSocket* sock)> msgHandle;
class TcpSocket : public QTcpSocket
{
Q_OBJECT
public:
explicit TcpSocket(qint32 id,qintptr socketDescriptor,msgHandle t_msg_handle=nullptr,QObject *parent = nullptr);
~TcpSocket();
signals:
void socketClose(qint32);
public slots:
void msgTimeout();
void readMessage();
void socketErr(QAbstractSocket::SocketError tError);
void socketdisconnect();
private:
qint32 m_id;
msgHandle m_msg_handle;
QTimer *m_msg_timeout;
};
#endif // TCPSOCKET_H
tcpsocket.cpp
#include "tcpsocket.h"
#include <QByteArray>
#include <QHostAddress>
#include <QDebug>
static const qint32 TIMEOUT_VALUE=30000;
TcpSocket::TcpSocket(qint32 id,qintptr socketDescriptor,msgHandle t_msg_handle,QObject *parent) :
QTcpSocket(parent),
m_id(id),
m_msg_handle(t_msg_handle)
{
m_msg_timeout =new QTimer(this);
connect(this->m_msg_timeout,SIGNAL(timeout()),this,SLOT(msgTimeout()));
this->setSocketDescriptor(socketDescriptor);
connect(this, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(socketErr(QAbstractSocket::SocketError)));
connect(this,SIGNAL(disconnected()),this,SLOT(socketdisconnect()));
connect(this, SIGNAL(readyRead()), this, SLOT(readMessage()));
this->m_msg_timeout->start(TIMEOUT_VALUE);
}
TcpSocket::~TcpSocket()
{
this->disconnectFromHost();
}
void TcpSocket::msgTimeout()
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"socket connect free timeout"<<endl;
this->disconnectFromHost();
}
void TcpSocket::readMessage()
{
this->m_msg_timeout->stop();
QByteArray t_message=this->readAll();
if(this->m_msg_handle!=nullptr)
{
m_msg_handle(t_message,this);
}
this->m_msg_timeout->start(TIMEOUT_VALUE);
}
void TcpSocket::socketErr(QAbstractSocket::SocketError tError)
{
qDebug()<<__FILE__<<":"<<__LINE__<<":"<<"id: "<<this->socketDescriptor()<<"socket error: "<<this->errorString()<<endl;
switch (tError)
{
case QAbstractSocket::RemoteHostClosedError:
this->disconnectFromHost();
break;
default:
this->disconnectFromHost();
break;
}
}
void TcpSocket::socketdisconnect()
{
emit socketClose(this->m_id);
this->deleteLater();
}
|