Qt框架下服务器的实现

avatar
作者
筋斗云
阅读量:5

一、前言

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代表等待中断。

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!