欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

使用QTcpServer创建一个简单的服务器程序之二:多线程服务器(4)-服务端实现

程序员文章站 2024-03-20 17:19:22
...

前面说了服务端类MyTcpServer只负责监听连入的客户端,并把这个客户端丢入线程池中。并且还要接收来自界面类的一些请求,并最终通过它管理的线程池来实现。这其中最重要函数就是重写incomingConnection

//这里包含一个线程池的对象和一个客户端链表
    MyThreadPool m_pool;//线程池
    QList<MyTcpSocket*> m_list;//维护一个客户端的列表,这个列表只是给界面显示使用,具体的和客户端通信都是交给线程池去完成

//还要改写最大连接数,不然默认的只能连接30个,这里我传入的是1000
void MyTcpServer::setMaxPendingConnections(int numConnections)
{
    QTcpServer::setMaxPendingConnections(numConnections);
}

//核心步骤,重写该函数,接管客户端socket连接进来后的操作
void MyTcpServer::incomingConnection(qintptr handle)
{
    //把客户端socket放入正确的线程中
    MyTcpSocket *pSocket = m_pool.AssignClient(handle);

    //注意!!!!!!!!!!!!!!!!!!!要用得到的实际信息设置pSocket对象中两个成员变量
    pSocket->setIP(pSocket->peerAddress().toString());
    pSocket->setPort(pSocket->peerPort());

    //加入客户端列表
    QMutexLocker lock(&m_lock);
    m_list.append(pSocket);

    //通知主界面,有新客户端加入
    emit SignalNewClient(pSocket);
}

负责和客户端通信的MyTcpSocket很简单,只要记录这个客户端的IP地址、端口号和socket描述符信息即可。

class MyTcpSocket : public QTcpSocket
{
    Q_OBJECT
public:
    explicit MyTcpSocket(qintptr socketDescriptor, QObject *parent = 0);

private:
    QString ip;
    int port;
    qintptr socketID;

public:
    void setIP(const QString &ip);
    QString getIP()const;

    void setPort(int port);
    int getPort()const;

    qintptr getSocketID() const;

public slots:
    void SlotWriteData(const int handle,const QByteArray &buf);//发数据

};


MyTcpSocket::MyTcpSocket(qintptr socketDescriptor, QObject *parent) :
    QTcpSocket(parent),socketID(socketDescriptor)
{
    ip = "127.0.0.1";
    port = 6000;
    this->setSocketDescriptor(socketDescriptor);//传入socket描述符
    //connect(this,&MyTcpSocket::disconnected,this,&MyTcpSocket::deleteLater);
}

void MyTcpSocket::setIP(const QString &ip)
{
    this->ip = ip;
}

QString MyTcpSocket::getIP() const
{
    return this->ip;
}

void MyTcpSocket::setPort(int port)
{
    this->port = port;
}

int MyTcpSocket::getPort() const
{
    return this->port;
}

qintptr MyTcpSocket::getSocketID() const
{
    return socketID;
}

void MyTcpSocket::SlotWriteData(const int handle,const QByteArray &buf)
{
    if(socketID == (qintptr)handle)
        write(buf);
}

到这里这个简单的服务器程序就写的差不多了。当然,这只是一个简单的示例程序,还有很多可以改进的地方,我现在能想到的有以下几个地方:

1,放入线程池中的客户端指针可以采用智能指针,这样的话处理断开连接的信号时,客户端可以先处理自己的disconnect,然后再去处理线程池中的存放在指针以及服务端维护的客户端链表。

2,每个客户端类还可以带一个大一点的数据缓冲区,防止数据发送频繁时有数据丢失。

3,多线程处理的地方不知道有没有问题,我没有彻底的检查

4,真正进行服务端/客户端通信时,需要对信息进行封包和拆包处理,包括心跳机制等,我这里测试用的就是简单的发送字符串。

相关标签: Qt