源码地址:https://github.com/haidragon/easyChat 思路 :

  1. 一个服务器一直接听某个 ip 的某个端口 listen(QHostAddress::Any,port); 2.一个服务器有一个容器保存所有各客服端的链接(每个链接都是一个类)。QList<TcpClientSocket*> tcpClientSocketList;每当一个客服端链接上那个服务器一直接听的套节字时。服务器会自动调用一个函数。incomingConnection(qintptr socketDescriptor);(这个函数是继承过来的虚函数) 3.每次调用链接函数时 new 一个新的客服端流(也就是另外增加一个类。这个类就是客服端流类)TcpClientSocket *tcpClientSocket=new TcpClientSocket(this); 4.服务器管理所有的服端流。 5.每次新创建一个客服端流时会往流里写入链接成功的数据。
//链接后就往套节字里发内容
void TcpClient::slotConnected()
{
    sendBtn->setEnabled(true);
    enterBtn->setText(tr("离开"));

    int length=0;
    QString msg=userName+tr(":Enter Chat Room");
    if((length=tcpSocket->write(msg.toLatin1(),msg.length()))!=msg.length())
    {
        return;
    }
}

6.由于每个客服端流是分开的只有服务器能够知道所有流里的数据。因此每当有客服端流中有数据时在服务器中会发给其它客服端流。其它客服端流只要流中有数据会一直更新。实现了简单群聊。

void Server::updateClients(QString msg,int length)
{
    emit updateServer(msg,length);
    //这里是往每个链接里与 
    for(int i=0;i<tcpClientSocketList.count();i++)
    {
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->write(msg.toLatin1(),length)!=length)
        {
            continue;
        }
    }
}

7.服务器端也实现了 ui 见面 8.每个客服端只要断开链接。它就会在这个流中发一个断开信号。因为服务器保存了每个客服端的流。当某个客服端流断开时会发一个断开信号同时带上标志。服务器只要检测到了这个信号会及时处理。

  else
    {
        int length=0;
        QString msg=userName+tr(":Leave Chat Room");
        if((length=tcpSocket->write(msg.toLatin1(),msg.length()))!=msg. length())
        {
            return;
        }

        tcpSocket->disconnectFromHost();

        status=false;
    }
		
		/////////  tcpclientsocket类
		void TcpClientSocket::slotDisconnected()
{
    emit disconnected(this->socketDescriptor());
}
///server类
void Server::slotDisconnected(int descriptor)
{
    for(int i=0;i<tcpClientSocketList.count();i++)
    {
        QTcpSocket *item = tcpClientSocketList.at(i);
        if(item->socketDescriptor()==descriptor)
        {
            tcpClientSocketList.removeAt(i);
            return;
        }
    }
    return;
}