QT基于TCP传输的实现(服务器端)

一.环境配置

系统:win11(win10运行需注意运行库更新到新版本)

Qt版本:Qt.6.3以上

ip和端口:IP可以自动获取,端口这里设置为1201,注意项目部署的时候服务器端需要配置(windows防火墙高级设置,新建输出端口1201,也可以自定)

二.前言

本实验是实现tcp通讯功能,客户端连接上服务器端后,可以与服务器端互发消息

三.所需库函数介绍

1.QT       += network

实现qt网络功能的模块,不过多赘述

2.#include<QTcpServer>

   公共函数:

   

   信号:

  

3.#include<QTcpSocket>

     成员函数:

     

四.正文

     1.UI界面预设:

     

     2.主函数

     初始化预设的指针以及状态栏label,并且获取服务器的地址更新comboip

ui->setupUi(this);
    tcpserver=new QTcpServer(this);

    //lablisten初始化并添加到状态栏上面
    labListen =new QLabel("监听状态:");
    labListen->setMinimumWidth(150);
    ui->statusBar->addWidget(labListen);

    //labsocket初始化并添加到状态栏上面
    labSocketState= new QLabel("Socket状态:");
    labSocketState->setMinimumWidth(150);
    ui->statusBar->addWidget(labSocketState);

    //获取服务器的信息,包括名字IP等,并添加在comboIP中
    QString name=QHostInfo::localHostName();
    QHostInfo hostinfo=QHostInfo::fromName(name);
    QString localIp ;
    foreach (const auto &item, hostinfo.addresses()) {
        if(item.protocol()==QAbstractSocket::IPv4Protocol){
            localIp=item.toString();
            ui->comboIP->addItem(localIp);
        }
    }
    connect(tcpserver,&QTcpServer::newConnection,this,&MainWindow::do_newConnection);//每次有新连接可用的时候都会发送newConnection信号
}

其中connect是处理获取到新连接信号的时候,触发do_newConnection槽函数:

void MainWindow::do_newConnection()
{
    tcpsocket=tcpserver->nextPendingConnection();//将tcpsocket指向被监听到的端口
    connect(tcpsocket,&QTcpSocket::connected,this,&MainWindow::do_connected);
    connect(tcpsocket,&QTcpSocket::disconnected,this,&MainWindow::do_disconnected);
    connect(tcpsocket,&QTcpSocket::readyRead,this,&MainWindow::do_readyRead);
    connect(tcpsocket,&QTcpSocket::stateChanged,this,&MainWindow::do_stateChanged);
    // 手动触发 stateChanged 信号
    emit tcpsocket->stateChanged(tcpsocket->state());
}

&QTcpSocket::connected:连接信号触发

&QTcpSocket::disconnected:断开连接信号触发

&QTcpSocket::readyRead:当读取缓冲区收到数据流时触发该信号

&QTcpSocket::stateChanged:当socket状态改变时候触发该信号

emit tcpsocket->stateChanged(tcpsocket->state());:手动触发 stateChanged 信号,不手动触发的话有客户端连接上状态栏socket状态标签会没变化

上面四个信号触发时调用的对应的槽函数:

void MainWindow::do_connected()
{
    ui->textEdit->appendPlainText("**client socket connected**");
    ui->textEdit->appendPlainText("peer name:"+tcpsocket->peerName());
    ui->textEdit->appendPlainText("peer address:"+tcpsocket->peerAddress().toString());
    ui->textEdit->appendPlainText("peer port:"+QString::number(tcpsocket->peerPort()));
}

void MainWindow::do_disconnected()
{
    ui->textEdit->appendPlainText("**client socket disconnected**");
    tcpsocket->deleteLater();//并不是马上删除,而是等待一些事务处理完后才删除socket
    tcpsocket = nullptr; // 设置为 nullptr,避免悬空指针
}

void MainWindow::do_readyRead()//当有数据传过来的时候,我们要消费这些数据
{
    while (tcpsocket->canReadLine()) {
        ui->textEdit->appendPlainText("[in] "+tcpsocket->readLine());
    }
}

void MainWindow::do_stateChanged(QAbstractSocket::SocketState state)
{
    switch (state) {
    case QAbstractSocket::UnconnectedState:
        labSocketState->setText("socket状态:UnconnectedState");
        break;
    case QAbstractSocket::HostLookupState:
        labSocketState->setText("socket状态:HostLookupState");
        break;
    case QAbstractSocket::ConnectingState:
        labSocketState->setText("socket状态:ConnectingState");
        break;
    case QAbstractSocket::ConnectedState:
        labSocketState->setText("socket状态:ConnectedState");
        break;
    case QAbstractSocket::BoundState:
        labSocketState->setText("socket状态:BoundState");
        break;
    case QAbstractSocket::ListeningState:
        labSocketState->setText("socket状态:ListeningState");
        break;
    case QAbstractSocket::ClosingState:
        labSocketState->setText("socket状态:ClosingState");
        break;
    }
}

其中SocketState是枚举类:

3.开始监听功能

获取ui界面上面的IP和端口号,调用tcpserver->listen开始监听,第一个参数是ip地址,第二个的参数是端口号

//开始监听
void MainWindow::on_actStart_triggered()
{
    QString IP=ui->comboIP->currentText();
    quint16 port=ui->spinPort->value();
    QHostAddress hostaddress(IP);
    tcpserver->listen(hostaddress,port);
    ui->textEdit->appendPlainText("**开始监听**");
    ui->textEdit->appendPlainText("服务器地址:"+tcpserver->serverAddress().toString());
    ui->textEdit->appendPlainText("服务器端口号:"+QString::number(tcpserver->serverPort()));
    ui->actStart->setEnabled(false);
    ui->actStop->setEnabled(true);
    labListen->setText("监听状态:正在监听...");
}

4.停止监听

当tcpsocket不是空指针并且socket是连接状态时,调用disconnectFromHost()断开socket连接

//停止监听
void MainWindow::on_actStop_triggered()
{
    if(tcpsocket!=nullptr&&tcpsocket->state()==QAbstractSocket::ConnectedState){
        tcpsocket->disconnectFromHost();
    }
    //设置act状态
    ui->actStart->setEnabled(true);
    ui->actStop->setEnabled(false);
    //停止监听
    if(tcpserver->isListening()){
        tcpserver->close();
        labListen->setText("监听状态:监听已停止");
    }
}

5.发送消息

//发送消息
void MainWindow::on_btnSend_clicked()
{
    //如果消息框为空,不发送
    bool x =ui->editMsg->text().isEmpty();
    if(x){
        ui->textEdit->appendPlainText("消息框为空");
        return;}
    //如果没有链接,不发送
    if(tcpsocket==nullptr){
        ui->textEdit->appendPlainText("链接没有建立");
        return;}
    //将消息框内容通过socket发送出去,并在聊天框中显示出来
    QString message=ui->editMsg->text();
    ui->textEdit->appendPlainText("[out]: "+message);
    QByteArray ms=message.toUtf8();
    ms.append("\n");
    tcpsocket->write(ms);
    ui->editMsg->clear();
}

因为数据的读取用的是readline,是一行一行读取,以换行符作为一串数据结束识别的符号,所以如果要用readline注意要在数据后面加上\n

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值