QT網絡編程須要在配置文件中添加網絡模塊的配置文件編程
#---添加網絡模塊配置--- QT += network
界面設計
服務器
獲取主機按鈕槽函數網絡
//獲取主機信息按鈕事件 void MainWindow::on_btn_host_clicked() { //hostinfo獲取主機的信息 QString hostName=QHostInfo::localHostName();//獲取本機的主機名 ui->plainTextEdit->appendPlainText("主機名爲:"+hostName+"\n"); QHostInfo hostInfo=QHostInfo::fromName(hostName);//經過主機名來獲取主機的hostinfo QList<QHostAddress> addList=hostInfo.addresses();//經過主機的host信息來獲取本機IP地址列表 if(!addList.isEmpty())//若是主機地址列表不爲空 { for(int i=0;i<addList.length();i++) { QHostAddress hostAddress=addList.at(i); //每一項是一個hostAddress bool show=ui->cbxShowIPV4->isChecked();//是否選中 if(show) { show=(QAbstractSocket::IPv4Protocol==hostAddress.protocol()); } else { show=true; } if(show) { ui->plainTextEdit->appendPlainText("協議:"+protocalName(hostAddress.protocol())); ui->plainTextEdit->appendPlainText("本機IP地址:"+hostAddress.toString()); ui->plainTextEdit->appendPlainText(""); } } } }
按照主機名,IP地址,域名來查找主機信息app
//按照主機的主機名,IP地址,域名來查找主機信息 void MainWindow::on_btnFindIP_clicked() { //查找主機信息 QString hostName=ui->txtHostName->text(); ui->plainTextEdit->appendPlainText("正在查找"+hostName+"主機的信息"); //lookupHost()以異步的方式查找主機信息,查找完成後經過信號通知槽函數 QHostInfo::lookupHost(hostName,this,SLOT(lookedUpHostInfo(QHostInfo))); }
查找主機信息槽函數異步
//查找主機信息 void MainWindow::lookedUpHostInfo(const QHostInfo & hostInfo) { QList<QHostAddress> listAdd=hostInfo.addresses(); if(!listAdd.isEmpty()) { for(int i=0;i<listAdd.length();i++) { QHostAddress add=listAdd.at(i); bool show=ui->cbxShowIPV4->isChecked(); if(show) { show=(QAbstractSocket::IPv4Protocol==add.protocol()); } else { show=true; } if(show) { ui->plainTextEdit->appendPlainText("協 議:"+protocalName(add.protocol())); ui->plainTextEdit->appendPlainText(add.toString()); ui->plainTextEdit->appendPlainText(""); } } } }
//只獲取IP地址QNetworkInterface::allAddress()socket
//只獲取IP地址QNetworkInterface::allAddress() void MainWindow::on_btn_network_clicked() { QList<QHostAddress> listHost=QNetworkInterface::allAddresses(); if(!listHost.isEmpty()) { for(int i=0;i<listHost.length();i++) { QHostAddress address=listHost.at(i); bool show=ui->cbxShowIPV4->isChecked(); if(show) { show=(QAbstractSocket::IPv4Protocol==address.protocol()); } else { show=true; } if(show) { ui->plainTextEdit->appendPlainText("協 議:"+protocalName(address.protocol())); ui->plainTextEdit->appendPlainText("IP地址:"+address.toString()); ui->plainTextEdit->appendPlainText(""); } } } }
QNetworkInterface能夠獲取應用程序所在主機的全部網絡接口,包括其子網掩碼和廣播地址等tcp
void MainWindow::on_btnNetwoklInterface_clicked() { QList<QNetworkInterface> list=QNetworkInterface::allInterfaces();//獲取全部的網絡接口 for(int i=0;i<list.length();i++) { QNetworkInterface interface=list.at(i); if(!interface.isValid()) { continue; } ui->plainTextEdit->appendPlainText("設備名稱:"+interface.humanReadableName()); ui->plainTextEdit->appendPlainText("硬件地址:"+interface.hardwareAddress()); QList<QNetworkAddressEntry> entryList=interface.addressEntries(); for(int j=0;j<entryList.length();j++) { QNetworkAddressEntry aEntry=entryList.at(j); ui->plainTextEdit->appendPlainText(" IP 地址:"+aEntry.ip().toString()); ui->plainTextEdit->appendPlainText(" 子網掩碼:"+aEntry.netmask().toString()); ui->plainTextEdit->appendPlainText(" 廣播地址:"+aEntry.broadcast().toString()+"\n"); } ui->plainTextEdit->appendPlainText("\n"); } }
TCP Client客戶端界面以下圖:
函數
鏈接服務器ui
//鏈接服務器 void MainWindow::on_actConnectServer_triggered() { QString addr=ui->cbbxServerAdd->currentText();//服務器IP地址 quint16 port=ui->spbPort->value();//服務器端口號 tcpSocket->connectToHost(addr,port);//鏈接服務器 lblSocketState->setText("Socket狀態:正在鏈接"); }
客戶端鏈接上服務器後tcpClient會發射connected()信號,對應的槽函數以下:this
void MainWindow::onConnected() { ui->plainTextEdit->appendPlainText("**已鏈接到服務器"); ui->plainTextEdit->appendPlainText("**peer address:"+tcpSocket->peerAddress().toString()); ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpSocket->peerPort())); ui->actConnectServer->setEnabled(false); ui->actDisconnect->setEnabled(true); lblSocketState->setText("Socket狀態:已鏈接"); }
客戶端鏈接狀態發生變化會觸發stateChanged(QAbstractSocket::SocketState))信號,對應的槽函數代碼以下
void MainWindow::onSocketStateChanged(QAbstractSocket::SocketState state) { switch(state) { case QAbstractSocket::UnconnectedState: lblSocketState->setText("socket狀態:UnconnectedState"); break; case QAbstractSocket::HostLookupState: lblSocketState->setText("socket狀態:HostLookupState"); break; case QAbstractSocket::ConnectingState: lblSocketState->setText("socket狀態:ConnectingState"); break; case QAbstractSocket::ConnectedState: lblSocketState->setText("socket狀態:ConnectedState"); break; case QAbstractSocket::BoundState: lblSocketState->setText("socket狀態:BoundState"); break; case QAbstractSocket::ClosingState: lblSocketState->setText("socket狀態:ClosingState"); break; case QAbstractSocket::ListeningState: lblSocketState->setText("socket狀態:ListeningState"); break; } }
客戶端向服務端發送數據:Socket之間的數據通訊協議通常有兩種方式,基於行的或基於數據塊的;基於行的數據通訊協議通常用於純文本數據的通訊,每一行數據以一個換行符結束。基於數據塊的數據通訊協議用於通常的二進制數據的傳輸,須要自定義數據的格式。下面爲客戶端向服務器發送數據的代碼:
void MainWindow::on_btnSend_clicked() { QString msg=ui->txtSend->text(); ui->plainTextEdit->appendPlainText("[out] "+msg); ui->txtSend->clear(); ui->txtSend->setFocus(); QByteArray str=msg.toUtf8(); str.append('\n'); tcpSocket->write(str); }
當服務器向客戶端發送數據的時候,客戶端收到數據會觸發readyRead()信號,對應的槽函數代碼以下:
void MainWindow::onSocketReadyRead() { while(tcpSocket->canReadLine()) { ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine()); } }
斷開與服務器的鏈接代碼以下:
void MainWindow::on_actDisconnect_triggered() { if(tcpSocket->state()==QAbstractSocket::ConnectedState) { tcpSocket->disconnectFromHost();//斷開鏈接 } }
TCP Server Demo的界面設計以下:
初始化服務器對象,添加有新的客戶端接入的信號與槽。
tcpServer=new QTcpServer(this); connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));//添加tcp客戶端鏈接上發送信號newConnection和對應的槽函數關聯
開啓服務監聽代碼以下:
void MainWindow::on_actListenning_triggered() { QString ip=ui->cbbxListenAdd->currentText();//IP地址 quint16 port=ui->spbxPort->value();//端口號 QHostAddress add(ip); tcpServer->listen(add,port); ui->plainTextEdit->appendPlainText("**開始監聽。。"); ui->plainTextEdit->appendPlainText("**服務器地址:"+tcpServer->serverAddress().toString()); ui->plainTextEdit->appendPlainText("服務器端口號:"+QString::number(tcpServer->serverPort())); ui->actListenning->setEnabled(false); ui->actStopListening->setEnabled(true); lblListeningState->setText("監聽狀態:正在監聽"); }
當有新客戶端鏈接上時觸發的槽函數
//新用戶鏈接上觸發的槽函數 void MainWindow::onNewConnection() { tcpSocket=tcpServer->nextPendingConnection();//獲取新鏈接上的tcp客戶端Socket對象 //添加信號已鏈接的信號與槽 connect(tcpSocket,SIGNAL(connected()),this,SLOT(onClientConnected())); onClientConnected(); //添加客戶端與服務器斷開的信號與槽 connect(tcpSocket,SIGNAL(disconnected()),this,SLOT(onClientDisconnected())); //添加鏈接的socket狀態變化的信號與槽 connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),this,SLOT(onSocketStateChanged(QAbstractSocket::SocketState))); onSocketStateChanged(tcpSocket->state()); //添加有數據到達的信號與槽 connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead())); }
客戶端鏈接上服務器觸發的槽函數以下:
void MainWindow::onClientConnected() { ui->plainTextEdit->appendPlainText("客戶端socket已經鏈接"); ui->plainTextEdit->appendPlainText("客戶端地址:"+tcpSocket->peerAddress().toString()); ui->plainTextEdit->appendPlainText("客戶端端口號:"+QString::number(tcpSocket->peerPort())); }
Socket狀態發生變化的槽函數以下:
void MainWindow::onSocketStateChanged(QAbstractSocket::SocketState socketState) { switch(socketState) { case QAbstractSocket::UnconnectedState: lblSocketState->setText("socket狀態:UnconnectedState"); break; case QAbstractSocket::HostLookupState: lblSocketState->setText("socket狀態:HostLookupState"); break; case QAbstractSocket::ConnectingState: lblSocketState->setText("socket狀態:ConnectingState"); break; case QAbstractSocket::ConnectedState: lblSocketState->setText("socket狀態:ConnectedState"); break; case QAbstractSocket::BoundState: lblSocketState->setText("socket狀態:BoundState"); break; case QAbstractSocket::ClosingState: lblSocketState->setText("socket狀態:ClosingState"); break; case QAbstractSocket::ListeningState: lblSocketState->setText("socket狀態:ListeningState"); break; } }
客戶端斷開了與服務端的連接觸發的槽函數以下:
void MainWindow::onClientDisconnected() { ui->plainTextEdit->appendPlainText("客戶端已經斷開鏈接"); tcpSocket->deleteLater(); }
服務端向客戶端發送數據的代碼以下:
//消息發送 //socket數據之間的數據通訊協議通常有兩種,基於行或者基於數據塊 //基於行的通訊通常用於純文本通訊 void MainWindow::on_btnSend_clicked() { QString msg=ui->txtSend->text(); ui->plainTextEdit->appendPlainText("[out] "+msg); ui->txtSend->clear(); ui->txtSend->setFocus(); QByteArray str=msg.toUtf8(); str.append('\n'); tcpSocket->write(str); }
服務端收到客戶端數據槽函數代碼以下:
void MainWindow::onSocketReadyRead() { while(tcpSocket->canReadLine()) { ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readLine()); } }
關閉服務端監聽代碼以下:
void MainWindow::on_actStopListening_triggered() { if(tcpServer->isListening())//若是正在監聽 { tcpServer->close(); ui->actListenning->setEnabled(true); ui->actStopListening->setEnabled(false); lblListeningState->setText("監聽狀態:中止監聽"); } }
界面設計以下:
綁定端口代碼以下:
//綁定端口 void MainWindow::on_actBundPort_triggered() { quint16 localPort=ui->spbBindPort->value(); if(udpSocket->bind(localPort))//若是端口綁定成功 { ui->plainTextEdit->appendPlainText("**已成功綁定"); ui->plainTextEdit->appendPlainText("**綁定端口:"+QString::number(udpSocket->localPort())); ui->actBundPort->setEnabled(false); ui->actDisBund->setEnabled(true); } else { ui->plainTextEdit->appendPlainText("**綁定失敗"); } }
單播發送消息代碼以下:
//發送消息 void MainWindow::on_btnSend_clicked() { //目標IP地址 QString aimIP=ui->cbbxAimAddress->currentText(); //目標計算機Host地址 QHostAddress aAddress(aimIP); //目標端口號 quint16 port=ui->spbAimPort->value(); QString msg=ui->txtSend->text(); //字符串轉QByteArray QByteArray str=msg.toUtf8(); //單播發送數據包 udpSocket->writeDatagram(str,aAddress,port);//發送數據包,通常數據包的長度最大不超過512字節 ui->plainTextEdit->appendPlainText("[out] "+msg); ui->txtSend->clear(); ui->txtSend->setFocus(); }
廣播發送消息,廣播消息的時候須要將目標地址更換爲特殊的地址,即廣播地址:QHostAddress::Broadcast通常爲255.255.255.255,廣播發送消息代碼以下:
//廣播消息 void MainWindow::on_btnBoardcast_clicked() { quint16 aimPort=ui->spbAimPort->value(); QString msg=ui->txtSend->text(); QByteArray str=msg.toUtf8(); udpSocket->writeDatagram(str,QHostAddress::Broadcast,aimPort); ui->plainTextEdit->appendPlainText("[boardcast] "+msg); ui->txtSend->clear(); ui->txtSend->setFocus(); }
讀取數據報數據代碼以下:
//讀取數據報數據 void MainWindow::onSocketReadyRead() { while(udpSocket->hasPendingDatagrams()) { QByteArray datagram; datagram.resize(udpSocket->pendingDatagramSize()); QHostAddress peerAddress; quint16 peerPort; udpSocket->readDatagram(datagram.data(),datagram.size(),&peerAddress,&peerPort); QString str=datagram.data(); QString peer="[from "+peerAddress.toString()+QString::number(peerPort)+"] "; ui->plainTextEdit->appendPlainText(peer+str); } }
UDP解除綁定的端口號代碼以下:
void MainWindow::on_actDisBund_triggered() { udpSocket->abort(); ui->actBundPort->setEnabled(true); ui->actDisBund->setEnabled(false); ui->plainTextEdit->appendPlainText("**已解除綁定"); }
採用UDP組播必須使用一個組播地址,組播地址是D類IP地址,關於組播地址有以下的一下約定,以下圖所示:
UDP組播 Demo界面設計以下圖所示:
組播UDP的初始化,代碼以下:
udpSocket=new QUdpSocket(this); udpSocket->setSocketOption(QAbstractSocket::MulticastTtlOption,1);//MulticastTtlOption爲組播數據報的生存週期,數據報每誇一個路由會減1;缺省值爲1表示多播數據報只能在同一路由的局域網內傳播
加入組播代碼:
//加入組播槽函數 void MainWindow::on_actAddMulticast_triggered() { QString ip=ui->cbbxMulticastAddr->currentText(); groupAddress=QHostAddress(ip);//組播地址 quint16 groupPort=ui->spbPort->value(); if(udpSocket->bind(QHostAddress::AnyIPv4,groupPort,QUdpSocket::ShareAddress))//綁定端口 { udpSocket->joinMulticastGroup(groupAddress); ui->plainTextEdit->appendPlainText("加入組播成功!"); ui->plainTextEdit->appendPlainText("組播地址IP:"+ip); ui->plainTextEdit->appendPlainText("**綁定的端口:"+QString::number(groupPort)); ui->actAddMulticast->setEnabled(false); ui->actExitMulticast->setEnabled(true); ui->cbbxMulticastAddr->setEnabled(false); } else { ui->plainTextEdit->appendPlainText("綁定端口失敗!"); } }
退出組播代碼以下:
//退出組播槽函數 void MainWindow::on_actExitMulticast_triggered() { udpSocket->leaveMulticastGroup(groupAddress);//退出組播 udpSocket->abort();//解除綁定 ui->actAddMulticast->setEnabled(true); ui->actExitMulticast->setEnabled(false); ui->cbbxMulticastAddr->setEnabled(true); ui->plainTextEdit->appendPlainText("**已退出組播,解除端口綁定"); }
其它接收發消息和廣播收發消息一致。