QT tcp服务端一对多,实现给多个客户端发送文件

用途:本来是用于给单片机收发消息的,只做了服务端,客户端是用别的网络调试助手测试。

展示

在这里插入图片描述
*不想看我逼逼的,源代码在这里:https://download.csdn.net/download/weixin_43387612/11943194

一、实现功能

  1. 显示客户端连接和客户端断开数量
  2. 给所有客户端发送文件,给单独选中的客户端发送文件(下拉框选择)
  3. 接收客户端发过来的指令(分别有进度条,下面16个io_in点亮,8个io_out)
    **补充:**最右边最下面的RUN按键没有具体功能,目前是摆设

二、正文

  1. 显示客户端连接和客户端断开数量

当有新的连接信号,就进入ServerWidget::v_SlotConnection槽函数

//处理客户端连接
    connect(tcpServer, &QTcpServer::newConnection, this, &ServerWidget::v_SlotConnection);

处理连接的函数

void ServerWidget::v_SlotConnection()
{
	...
	clients.append(tcpSocket);//客户端链表,有新的客户端就在末尾加入
	...
	//lcd控件 数字+1
	int_linkNum++;
    ui->linkNumber->display(int_linkNum);
    //在这里处理断开连接的客户端
    connect(tcpSocket, &QTcpSocket::disconnected, this, &ServerWidget::v_SlotDisconnection);
	...
}

处理断开连接的函数

void ServerWidget::v_SlotDisconnection()
{
    tcpSocket = (QTcpSocket *)this->sender();//得到发出信号的客户端
    QString temp = QString("[%1:%2]:退出").arg(tcpSocket->peerAddress().toString()).arg(tcpSocket->peerPort());
    ui->textEditReadonly->append(temp);
	//从链表中删除
    for(int i=0;i<clients.length();i++)
    {
        if(clients.at(i)->peerAddress() == tcpSocket->peerAddress())
        {
            if(clients.at(i)->peerPort() == tcpSocket->peerPort())
            {
                clients.removeAt(i);
                //下拉框去除该客户端
                ui->comboBox_clientLink->removeItem(i+1);
                break;
            }
        }
    }
    //lcd显示的数量减1
    int_linkNum--;
    ui->linkNumber->display(int_linkNum);
}

当某一个Object emit一个signal的时候,它就是一个sender,系统会记录下当前是谁emit出这个signal的,所以你在对应的slot里就可以通过 sender()得到当前是谁invoke了你的slot,对应的是QObject->d->sender.(解释的说明来源:链接: link.

  1. 给所有客户端发送文件,给单独选中的客户端发送文件(下拉框选择)

(1)给所有客户端发送文件
下拉框默认加一个"All connections"

//处理连接
void ServerWidget::MCU_send_file()
{
	...
	ui->comboBox_clientLink->addItem("All connections");
	...
//发送文件按钮
void ServerWidget::on_buttonFile_clicked()
{
    ui->buttonFile->setEnabled(false);
    //下拉框为第一个(即"All connections")
    if(ui->comboBox_clientLink->currentIndex()==0)
    {
        for(int i=0;i<clients.length();i++)
        {
        	//遍历的给所有客户端发送文件
            v_SendData(clients.at(i));
        }
    }
	...
}

(2)给单独选中的客户端发送文件(下拉框选择)
说明:下拉框activated信号的QString和int分别为下拉框的字符串和行数(从零开始)

void ServerWidget::on_comboBox_clientLink_activated(int index)
{
    qDebug()<<index;
    ...
    //选中客户端
    tcpSocket_choice=clients.at(index-1);
	...
}
//发送文件按钮
void ServerWidget::on_buttonFile_clicked()
{
    ...
    else
    {
        v_SendData(tcpSocket_choice);
    }
    ...
}

发送文件流程
1.读取

QByteArray outBlock;//读取文件缓冲区
void ServerWidget::on_buttonChoose_clicked()
{
	...
	//打开文件
    bool isOk = file.open(QIODevice::ReadOnly);
    ...
    outBlock=file.read(file.size());//读取文件
    file.close();
	...
}

2.发送

void ServerWidget::v_SendData(QTcpSocket *tcpSocket_sendfile)
{
    ...
    qint64 ret = tcpSocket_sendfile->write(outBlock,outBlock.size());
    tcpSocket->waitForBytesWritten();
    ...
}
  1. 接收客户端发过来的指令(分别有进度条,下面16个io_in点亮,8个io_out)
void ServerWidget::v_SlotConnection()
{
	...
	connect(tcpSocket, &QTcpSocket::readyRead, this, &ServerWidget::v_ReadDatafromclient);
	...
}
void ServerWidget::v_ReadDatafromclient()
{
	...
	//tcpSocket_choice为下拉框选中的客户端
	Fun_num = tcpSocket_choice->readAll().toInt();
	...
}

第一次写qt,有什么不对的地方请指出,谢谢

猜你喜欢

转载自blog.csdn.net/weixin_43387612/article/details/101998259