一、演示案例一
本案例中,服务端与客户端对数据的读取都是“行读取”
服务端
第一步:创建一个基于QMainWindow的窗体,类名采用默认值,然后设计窗体
第二步:类的定义
//省略了系统自定义的代码,只列出了自己定义的代码 #include <QTcpServer> #include <QTcpSocket> #include <QHostInfo> class MainWindow : public QMainWindow { private: QLabel *LabListen; //状态栏标签,显示监听状态 QLabel *LabSocketState;//状态栏标签,显示连接状态 QTcpServer *tcpServer; //TCP服务端对象 QTcpSocket *tcpSocket; //TCP通信的Socket QString getLocalIP(); //获取本机的IP地址 protected: void closeEvent(QCloseEvent *event); private slots: //一系列自定义槽函数 void onNewConnection(); //QTcpServer的newConnection()信号 void onSocketStateChange(QAbstractSocket::SocketState socketState); void onClientConnected(); //客户端连接 void onClientDisconneced();//客户端断开连接 void onSocketReadyRead(); //读取socket传入的数据 };
第三步:构造函数
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //设置spin可以输入的最大值 ui->spinPort->setMaximum(65585); LabListen=new QLabel(QStringLiteral("监听状态:")); LabSocketState=new QLabel(QStringLiteral("Socket状态:")); LabListen->setMinimumWidth(150); LabSocketState->setMinimumWidth(200); ui->statusBar->addWidget(LabListen); ui->statusBar->addWidget(LabSocketState); //调用自定义函数获取本机IP,并将IP设置为窗体标题和comboBox的项 QString localIP=getLocalIP(); this->setWindowTitle(this->windowTitle()+QStringLiteral("---本机IP:")+localIP);; ui->comboIP->addItem(localIP); //创建QTcpServer,并将QTcpServer的newConnection信号与自定义槽函数绑定 tcpServer=new QTcpServer(this); connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
第四步:自定义函数getLocalIP的实现
QString MainWindow::getLocalIP() { QString hostName=QHostInfo::localHostName(); //获取主机名 QHostInfo hostInfo=QHostInfo::fromName(hostName); //通过主机名获取主机信息 QString localIP=""; QList<QHostAddress> addList=hostInfo.addresses(); //通过主机信息获取主机地址列表 if(!addList.isEmpty()) { for(int i=0;i<addList.count();i++) { QHostAddress aHost=addList.at(i); if(QAbstractSocket::IPv4Protocol==aHost.protocol()) { localIP=aHost.toString(); break; } } return localIP; } }
第五步:开始监听按钮相应函数
void MainWindow::on_actStart_triggered() { //获取IP和端口 QString IP=ui->comboIP->currentText(); quint16 port=ui->spinPort->value(); //为服务端提供一个地址和端口,并开始监听 QHostAddress addr(IP); tcpServer->listen(addr,port); //设置组件的内容和状态 ui->plainTextEdit->appendPlainText(QStringLiteral("开始监听...")); ui->plainTextEdit->appendPlainText(QStringLiteral("服务器地址...")+tcpServer->serverAddress().toString()); ui->plainTextEdit->appendPlainText(QStringLiteral("服务器端口...")+QString::number(tcpServer->serverPort())); ui->actStart->setEnabled(false); ui->actStop->setEnabled(true); LabListen->setText(QStringLiteral("监听状态:正在监听...")); }
第六步:实现自定义的onNewConnection槽函数,当有客户端连接进来时执行该槽函数
void MainWindow::onNewConnection() { tcpSocket=tcpServer->nextPendingConnection();//获取连接客户端的socket套接字 //客户端socket连接建立时发射connected信号 connect(tcpSocket,SIGNAL(connected()),this,SLOT(onClientConnected())); onClientConnected(); //客户端socket连接断开时发射disconnected信号 connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(onClientDisconneced())); //本程序的socket状态变化时发生stateChanged信号 connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState))); //本程序的socket的读取缓冲区有新数据时发送此信号 connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead())); }
第七步:实现在onNewConnection槽函数中调用的另一些自定义槽函数(onSocketReadyRead在下面介绍)
void MainWindow::onClientConnected() { //打印客户端的信息 ui->plainTextEdit->appendPlainText(QStringLiteral("client socket connected")); ui->plainTextEdit->appendPlainText(QStringLiteral("peer address:")+tcpSocket->peerAddress().toString()); ui->plainTextEdit->appendPlainText(QStringLiteral("peer port:")+QString::number(tcpSocket->peerPort())); }
void MainWindow::onClientDisconneced() { //打印信息 ui->plainTextEdit->appendPlainText("client socket disconnected"); //稍后删除本次会话的socket tcpSocket->deleteLater(); }
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState) { //socket的各种状态 switch (socketState) { case QAbstractSocket::UnconnectedState: LabSocketState->setText(QStringLiteral("socket状态:UnconnectedState")); break; case QAbstractSocket::HostLookupState: LabSocketState->setText(QStringLiteral("socket状态:HostLookupState")); break; case QAbstractSocket::ConnectedState: LabSocketState->setText(QStringLiteral("socket状态:ConnectedState")); break; case QAbstractSocket::BoundState: LabSocketState->setText(QStringLiteral("socket状态:BoundState")); break; case QAbstractSocket::ClosingState: LabSocketState->setText(QStringLiteral("socket状态:ClosingState")); break; case QAbstractSocket::ListeningState: LabSocketState->setText(QStringLiteral("socket状态:ListeningState")); break; } }
第八步:停止监听按钮响应函数
void MainWindow::on_actStop_triggered() { //如果服务端处于监听状态,断开连接 if(tcpServer->isListening()) { tcpServer->close(); ui->actStart->setEnabled(true); ui->actStop->setEnabled(false); LabListen->setText(QStringLiteral("监听状态:已停止监听")); } }
第九步:发送消息按钮的相应函数
void MainWindow::on_btnSend_clicked() { //获取输入的内容 QString msg=ui->editMsg->text(); ui->plainTextEdit->appendPlainText(QStringLiteral("[out]:")+msg); ui->editMsg->clear(); ui->editMsg->setFocus(); //将数据转为字节数组,并在结尾加上换行符,然后发送一行数据出去 QByteArray str=msg.toUtf8(); str.append('\n'); tcpSocket->write(str); }
第十步:自定义onSocketReadyRead槽函数的实现(当缓冲区中有数据可以读取时,执行该槽函数)
void MainWindow::onSocketReadyRead() { //如果有一行数据可以读取,那么读取一行数据 while(tcpSocket->canReadLine()) { ui->plainTextEdit->appendPlainText(QStringLiteral("[in]:")+tcpSocket->readLine()); } }
客户端
第一步:创建一个基于QMainWindow的窗体,类名采用默认值,然后设计窗体
第二步:类的定义
////省略了系统自定义的代码,只列出了自己定义的代码 #include <QLabel> #include <QTcpServer> #include <QTcpSocket> #include <QHostInfo> class MainWindow : public QMainWindow { private: QLabel *LabSocketState;//状态栏标签,显示连接状态 QTcpSocket *tcpClient; //TCP通信的Socket QString getLocalIP(); //获取本机的IP地址 protected: void closeEvent(QCloseEvent *event); private slots: //一系列自定义槽函数 void onConnection(); void onDisconnection(); void onSocketStateChange(QAbstractSocket::SocketState socketState); void onSocketReadyRead(); //读取socket传入的数据 };
第三步:构造函数
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setupUi(this); //设置spin可以输入的最大值 ui->spinPort->setMaximum(65585); //创建socket对象 tcpClient=new QTcpSocket(this); LabSocketState=new QLabel(QStringLiteral("Socket状态:")); LabSocketState->setMinimumWidth(250); ui->statusBar->addWidget(LabSocketState); //获取自定义函数获取本机IP,并将IP设置为窗体标题和comboBox的项 QString localIP=getLocalIP(); this->setWindowTitle(this->windowTitle()+QStringLiteral("---本机IP:")+localIP);; ui->comboIP->addItem(localIP); //绑定一些列信号与槽 connect(tcpClient,SIGNAL(connected()),this,SLOT(onConnection())); connect(tcpClient,SIGNAL(disconnected()),this,SLOT(onDisconnection())); connect(tcpClient,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChange(QAbstractSocket::SocketState))); connect(tcpClient,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead())); }
第四步:自定义getLocalIP函数的实现
QString MainWindow::getLocalIP() { QString hostName=QHostInfo::localHostName(); //获取主机名 QHostInfo hostInfo=QHostInfo::fromName(hostName); //通过主机名获取主机信息 QString localIP=""; QList<QHostAddress> addList=hostInfo.addresses(); //通过主机信息获取主机地址列表 if(!addList.isEmpty()) { for(int i=0;i<addList.count();i++) { QHostAddress aHost=addList.at(i); if(QAbstractSocket::IPv4Protocol==aHost.protocol()) { localIP=aHost.toString(); break; } } return localIP; } }
第五步:连接到服务器按钮的相应函数
void MainWindow::on_actConnect_triggered() { //获取IP和端口,并连接到服务端 QString addr=ui->comboIP->currentText(); quint16 port=ui->spinPort->value(); tcpClient->connectToHost(addr,port); }
第六步:断开连接按钮的相应函数
void MainWindow::on_actDisconnect_triggered() { if(tcpClient->state()==QAbstractSocket::ConnectedState) tcpClient->disconnectFromHost(); }
第七步:自定义onConnection、onDisconnection槽函数
void MainWindow::onConnection() { //打印信息 ui->plainTextEdit->appendPlainText(QStringLiteral("已连接到服务器")); ui->plainTextEdit->appendPlainText(QStringLiteral("peer address:")+tcpClient->peerAddress().toString()); ui->plainTextEdit->appendPlainText(QStringLiteral("peer port:")+QString::number(tcpClient->peerPort())); ui->actConnect->setEnabled(false); ui->actDisconnect->setEnabled(true); }
void MainWindow::onDisconnection() { ui->plainTextEdit->appendPlainText(QStringLiteral("已断开与服务器的连接")); ui->actConnect->setEnabled(true); ui->actDisconnect->setEnabled(false); }
第八步:自定义onSocketReadyRead、onSocketStateChange槽函数的实现
void MainWindow::onSocketReadyRead() { //如果有一行数据可以读取,就读取 while(tcpClient->canReadLine()) ui->plainTextEdit->appendPlainText(QStringLiteral("[in]:")+tcpClient->readLine()); }
void MainWindow::onSocketStateChange(QAbstractSocket::SocketState socketState) { //socket的各种状态 switch (socketState) { case QAbstractSocket::UnconnectedState: LabSocketState->setText(QStringLiteral("socket状态:UnconnectedState")); break; case QAbstractSocket::HostLookupState: LabSocketState->setText(QStringLiteral("socket状态:HostLookupState")); break; case QAbstractSocket::ConnectedState: LabSocketState->setText(QStringLiteral("socket状态:ConnectedState")); break; case QAbstractSocket::BoundState: LabSocketState->setText(QStringLiteral("socket状态:BoundState")); break; case QAbstractSocket::ClosingState: LabSocketState->setText(QStringLiteral("socket状态:ClosingState")); break; case QAbstractSocket::ListeningState: LabSocketState->setText(QStringLiteral("socket状态:ListeningState")); break; } }
第九步:发送信息按钮的响应函数
void MainWindow::on_btnSend_clicked() { //获取输入的内容 QString msg=ui->editMsg->text(); ui->plainTextEdit->appendPlainText(QStringLiteral("[out]:")+msg); ui->editMsg->clear(); ui->editMsg->setFocus(); //将数据转为字节数组,并在结尾加上换行符,然后发送一行数据出去 QByteArray str=msg.toUtf8(); str.append('\n'); tcpClient->write(str); }
演示效果:
二、演示案例二
本案例中,服务端与客户端对数据的读取都是“字节读取”
客户端
//客户端类 class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; QTcpSocket* clientSocket; bool isConnect;//一个标志,用于判断是否连接服务器 private slots: void connectServerSlot(); void isConnectSlot(); void isDisConnectSlot(); void recvDataFromServerSlot(); void sendDataToServerSlot(); };
Widget::Widget(QWidget *parent) : QWidget(parent),isConnect(false),//初始化连接表示为false ui(new Ui::Widget) { ui->setupUi(this); clientSocket=new QTcpSocket(this); connect(ui->conServerBtn,SIGNAL(clicked()),this,SLOT(connectServerSlot()));//点击按钮连接/断开服务器 connect(clientSocket,SIGNAL(connected()),this,SLOT(isConnectSlot()));//连接成功后相应 connect(clientSocket,SIGNAL(disconnected()),this,SLOT(isDisConnectSlot()));//如果没有连接相应 connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendDataToServerSlot()));//点击按钮发送消息 } Widget::~Widget() { if(clientSocket->isOpen()) clientSocket->close();//关闭套接字 delete clientSocket;//释放套接字 delete ui; } void Widget::connectServerSlot() { if(!isConnect)//如果当前未连接 { QString ServerIp=ui->serverIpLEdit->text();//得到服务器IP QString Port=ui->portLEdit->text();//得到服务器端口号 clientSocket->connectToHost(QHostAddress(ServerIp),Port.toInt());//通过IP与端口号连接服务器 if(clientSocket->waitForConnected(1000))//如果等待一秒内连接成功 { QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("连接服务器成功")); isConnect=true; } else//如果连接超时 { clientSocket->disconnect();//套接字不连接 QMessageBox::warning(this,QStringLiteral("提示"),QStringLiteral("连接服务器失败")); } } else//如果当前连接 { clientSocket->close();//关闭套接字 QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("断开服务器成功")); isConnect=false; } } void Widget::isDisConnectSlot() { ui->conServerBtn->setText(QStringLiteral("连接服务器")); } void Widget::isConnectSlot() { ui->conServerBtn->setText(QStringLiteral("断开服务器")); //连接成功后,查看是否有数据发送过来 connect(clientSocket,SIGNAL(readyRead()),this,SLOT(recvDataFromServerSlot())); } void Widget::recvDataFromServerSlot()//接受数据 { QByteArray recvData=clientSocket->readAll();//以字节类型得到数据 ui->recvTBrowser->append(QStringLiteral("服务器:")+QString::fromLocal8Bit(recvData)); ui->recvSizeTBrowser->setText(QString::number(recvData.size())); } void Widget::sendDataToServerSlot()//发送数据出去 { QString sendData=ui->sendTEdit->toPlainText(); if(clientSocket->isOpen())//如果套接字处于打开状态 { clientSocket->write(sendData.toLocal8Bit());//写数据 ui->recvTBrowser->append(QStringLiteral("客户端:")+sendData); ui->sendSizeTBrowser->setText(QString::number(sendData.toLocal8Bit().size())); ui->sendTEdit->clear(); } }
服务端
//服务端类 class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); private: Ui::Widget *ui; QTcpServer* tcpServer;//服务 QTcpSocket* tcpServerSocket;//套接字 private: void showHostAddress(); private slots: void listenSlot(); void newConSlot(); void recvDataFromClientSlot(); void sendDataToClientSlot(); };
Widget::Widget(QWidget *parent) : QWidget(parent),ui(new Ui::Widget) { ui->setupUi(this); showHostAddress();//打印主机网络地址和端口 tcpServer=new QTcpServer(this); connect(ui->listenBtn,SIGNAL(clicked()),this,SLOT(listenSlot())); //点击按钮开启加监听 connect(tcpServer,SIGNAL(newConnection()),this,SLOT(newConSlot()));//如果外界有客户端连接 connect(ui->sendMsgBtn,SIGNAL(clicked()),this,SLOT(sendDataToClientSlot()));//点击按钮发送数据 } void Widget::showHostAddress() { //allAddresses:得到所有网络地址 QList<QHostAddress> addressList=QNetworkInterface::allAddresses(); foreach(QHostAddress address,addressList)//遍历网络地址 { if(address.isNull())//为空退出 continue; QAbstractSocket::NetworkLayerProtocol protocol=address.protocol();//得到网络地址类型 if(protocol!=QAbstractSocket::IPv4Protocol)//此处设置为判断是否为IPV4网络地址 continue; ui->ipComBox->addItem(address.toString());//如果是IPV4,添加进组合框 } } void Widget::listenSlot()//监听 { if(!tcpServer->isListening())//如果不处于监听状态,开启监听 { //如果监听成功,参数:1.服务器IP地址 2.服务器端口号 if(tcpServer->listen(QHostAddress(ui->ipComBox->currentText()),\ ui->portLEdit->text().toInt())) { QMessageBox::information(this,QStringLiteral("提示"),QStringLiteral("启动监听成功")); ui->listenBtn->setText(QStringLiteral("关闭监听")); } else { QMessageBox::warning(this,QStringLiteral("提示"),QStringLiteral("启动监听失败")); } } else//如果处于监听状态,关闭监听 { tcpServer->close();//关闭服务 tcpServerSocket->close();//关闭套接字 ui->clientTBrowser->clear(); ui->recvTBrowser->clear(); ui->recvSizeTBrowser->clear(); ui->sendSizeTBrowser->clear(); ui->listenBtn->setText(QStringLiteral("开启监听")); } } void Widget::newConSlot() { tcpServerSocket=tcpServer->nextPendingConnection();//得到传入的客户套接字 QString clientName=tcpServerSocket->peerName();//得到客户端的名称 QHostAddress clientAddress=tcpServerSocket->peerAddress();//得到客户端的网络地址 qint64 clientPort=tcpServerSocket->peerPort();//得到客户端的端口 ui->clientTBrowser->append(QStringLiteral("客户端名:")+clientName+"\n"); ui->clientTBrowser->append(QStringLiteral("客户端IP:")+clientAddress.toString()+"\n"); ui->clientTBrowser->append(QStringLiteral("客户端端口:")+QString::number(clientPort)+"\n"); connect(tcpServerSocket,SIGNAL(readyRead()),this,SLOT(recvDataFromClientSlot()));//等待外界数据传入 } void Widget::recvDataFromClientSlot() { QByteArray recvData=tcpServerSocket->readAll();//读取所有数据 ui->recvTBrowser->append(QStringLiteral("客户端:")+QString::fromLocal8Bit(recvData)); ui->recvSizeTBrowser->setText(QString::number(recvData.size())); } void Widget::sendDataToClientSlot() { QString sendData=ui->sendTEdit->toPlainText(); tcpServerSocket->write(sendData.toLocal8Bit());//向外发送数据 ui->recvTBrowser->append(QStringLiteral("服务端:")+sendData); ui->sendSizeTBrowser->setText(QString::number(sendData.toLocal8Bit().size())); ui->sendTEdit->clear(); }
演示效果
————————————————
版权声明:本文为CSDN博主「江南、董少」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:
https://blog.csdn.net/qq_41453285/article/details/100137925

