Qt框架下服务器的实现

一、前言

Qt框架提供了QTcpServe和QTcpSocket两种类实现TCP协议的相关连接,TCP协议不再过多赘述,以下主要讲述自机服务器和自机客户端的连接实现TCP协议通信的具体方式。

二、基本功能介绍

使用Qt网络模块之前需要在.pro文件种加入network

服务器端

绑定端口,并通过信号判断新连入客户机,同时输出相关内容,同时通过断连信号进行客户端的删除。

收信功能绑定读取信号槽函数,对所带数据进行读取显示。

发信功能找到对应的客户机地址和端口进行发信

客户机端

连接端口

收信功能绑定读取信号槽函数

发信功能直接将发送数据写入设备

三、具体原理和代码实现

在.pro文件中加入network

QT       += core gui network

初始化并分配指针空间

void Widget::Init()
{
    myClient = new QTcpSocket(this);

}

服务器端实现

1.ui设计

搭建IP地址框和端口框Line Edit,信息接收框和发送框Tetx Edit,两个PushButton进行绑定和发送

2.IP绑定

通过listen方法指示服务器侦听地址、地址和端口端口上的传入连接。如果端口为 0,则自动选择端口。如果 address 为 QHostAddress::Any,则服务器将侦听所有网络接口。

setEnable设置按钮是否可以使用

setMaxPendingConnection设置最大挂起客户机数量

void Widget::on_btn_bind_clicked()
{
    QString myAddr;
    //手动设置ip
    myAddr = ui->ledit_serv_addr->text();
    QString myPort = ui->ledit_serv_port->text();
    QString msg;
    bool ret = myServer->listen(QHostAddress(myAddr),myPort.toUInt());
    if(!ret)
    {
        msg = "绑定失败";
    }
    else
    {
        msg = "绑定成功";
        ui->btn_bind->setEnabled(false);
    }
    ui->textEdit->append(msg);
    myServer->setMaxPendingConnections(MAXNUM);
    connect(myServer,SIGNAL(newConnection()),this,SLOT(doProcessNewConnection()));
    connect(myServer,SIGNAL(acceptError(QAbstractSocket::SocketError)),
            this,SLOT(doProcessAcceptError(QAbstractSocket::SocketError)));

}
3.客户端连入

nextPendingConnection(),用于等待并接受下一个挂起的连接。当一个客户端请求连接时,服务器会将该连接挂起,等待服务器接受连接。nextPendingConnection()函数会阻塞当前线程,直到有一个连接被接受。一旦有连接被接受,会返回一个QTcpSocket对象。

此时对客户端的IP地址和端口号进行读取并显示

void Widget::doProcessNewConnection()
{
    client = myServer->nextPendingConnection();
    arrayClient.append(client);
    QString msg = QString("客户端[%1:%2] 连入!")
            .arg(client->peerAddress().toString())
            .arg(client->peerPort());
    ui->textEdit->append(msg);
    //客户端断开
    connect(client,SIGNAL(diconnected()),this,SLOT(doProcessDiconnected()));
    //读取内容
    connect(client,SIGNAL(readyRead()),this,SLOT(doProcessReadyRead()));
}
4.客户端退出

当客户端退出时,通过sender返回指向发送信号的对象的指针,同时遍历客户机列表删除对应的客户端

void Widget::doProcessDiconnected()
{
    QTcpSocket *client = (QTcpSocket *)this->sender();

    QString msg = QString("客户端[%1:%2] 退出!")
            .arg(client->peerAddress().toString())
            .arg(client->peerPort());
    ui->textEdit->append(msg);
    //删除对应客户端
    for(int i= 0;i<arrayClient.length();i++)
    {
        if(arrayClient.at(i)->peerAddress() == client->peerAddress())
        {
            if(arrayClient.at(i)->peerPort() == client->peerPort())
            {
                arrayClient.removeAt(i);
                break;
            }
        }
    }
}
5.接收信息

使用readyRead()信号,每当有新数据可用于从器件的当前读取通道读取时,该信号就会发出一次。将该信号内容进行循环读取并进行显示。

void Widget::doProcessReadyRead()
{
    QTcpSocket *client = (QTcpSocket *)this->sender();
    QString str1 = QString(QString("客户端[%1:%2] 说:")
            .arg(client->peerAddress().toString())
            .arg(client->peerPort()));
    QString msg;
    QString str2;
    while (!client->atEnd())
    {
        msg.append(QString(client->readAll()));
    }
    str2 = QString("%1%2").arg(str1).arg(msg);
    ui->textEdit->append(str2);
}
6.发送信息

读取输入的客户端IP和端口信息,遍历客户端列表,找到对应的客户端通过write进行数据写入。

void Widget::on_btn_send_clicked()
{
    QString ip = ui->ledit_client_ip->text();
    QString port = ui->ledit_client_port->text();
    //查找对应的客户
    for(int i=0;i<arrayClient.length();i++)
    {
        if(arrayClient.at(i)->peerAddress().toString()==ip)
        {
            if(arrayClient.at(i)->peerPort() == port.toUInt())
            {
                QString msg = ui->textEdit_2->toPlainText();\
                arrayClient.at(i)->write(msg.toUtf8());
                ui->textEdit_2->clear();
                break;
            }
        }
    }
}

客户机端实现

1.ui设计

搭建IP地址框和端口框Line Edit,信息接收框和发送框Tetx Edit,两个PushButton进行连接和发送

2.服务器连接

connectTohost对指定的IP地址和端口号进行连接,同时绑定四信号和槽函数

void Widget::on_btn_bind_clicked()
{
    QString servIp = ui->ledit_serv_addr->text();
    QString servPort = ui->ledit_serv_port->text();
    myClient->connectToHost(QHostAddress(servIp),servPort.toUInt());
    connect(myClient,SIGNAL(connected()),this,SLOT(doProcessConnected()));
    connect(myClient,SIGNAL(readyRead()),this,SLOT(dorProcessReadyRead()));
    connect(myClient,SIGNAL(disconnected()),this,SLOT(doProcessDisconnected()));
    connect(myClient,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(doProcessError(QAbstractSocket::SocketError)));

}
3.信息接收

readyRead信号进行读取,与服务器端相同

void Widget::dorProcessReadyRead()
{
    QString msg,str1,str2;
    str1 = QString(" 服务器[%1:%2] 说:")
            .arg(myClient->peerAddress().toString())
            .arg(myClient->peerPort());
    while(!myClient->atEnd())
    {
        str2.append(QString(myClient->readAll()));
    }
    msg = QString("%1%2").arg(str1).arg(str2);
    ui->textEdit->append(msg);
}
4.信息发送

write进行写入,与服务器端相同

void Widget::on_btn_send_clicked()
{
    QString msg = ui->textEdit_2->toPlainText();
    int ret = myClient->write(msg.toUtf8());
    if(ret<=0)
        return;
    ui->textEdit_2->clear();
}

四、关于端口号和地址

windows操作系统下,可以通过cmd进行IP地址和端口号的查询

IP地址查询:ipconfig

一般使用IPV4右侧的IP地址

端口号查询:netstat -na

TCP对应的端口号,其中LISTENING代表监听状态,ESTABLISHED代表已连接,TIME_WAIT代表结束访问,CLOSE_WAIT代表等待中断。

  • 15
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值