QT项目二:局域网聊天工具
作者:互联网
QT项目二:局域网聊天工具
参考《Qt及Qt Quick开发实战精解》,该书介绍的很详细,不做过多介绍。
末尾有源码下载地址
1.main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
2.widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTextCharFormat>
class QUdpSocket;
class TcpServer;
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
//枚举变量信息类型:消息、新用户加入、用户退出、文件名、拒绝接收文件
enum MessageType
{
Message,
NewParticipant,
ParticipantLeft,
FileName,
Refuse
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void newParticipant(QString userName, QString localHostName, QString ipAddress);
void participantLeft(QString userName, QString localHostName, QString time);
void sendMessage(MessageType type, QString serverAddress="");
void closeEvent(QCloseEvent *event);
QString getIp();
QString getUserName();
QString getMessage();
bool saveFile(const QString &fileName);
void hasPendingFile(QString userName, QString serverAddress,
QString clientAddress, QString fileName);
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;
quint16 port;
QString fileName;
TcpServer *server;
QColor color;
private slots:
void processPendingDatagrams();
void on_sendButton_clicked();
void getFileName(QString name);
void on_sendToolBtn_clicked();
void on_fontComboBox_currentFontChanged(const QFont &f);
void on_sizeComboBox_currentIndexChanged(const QString &arg1);
void on_boldToolBtn_clicked(bool checked);
void on_italicToolBtn_clicked(bool checked);
void on_underlineToolBtn_clicked(bool checked);
void on_colorToolBtn_clicked();
void currentFormatChanged(const QTextCharFormat &format);
void on_saveToolBtn_clicked();
void on_clearToolBtn_clicked();
void on_exitButton_clicked();
};
#endif // WIDGET_H
3.widget.cpp
#include <QUdpSocket>
#include <QHostInfo>
#include <QMessageBox>
#include <QScrollBar>
#include <QDateTime>
#include <QNetworkInterface>
#include <QProcess>
#include <QDebug>
#include <QFileDialog>
#include <QColorDialog>
#include <QThread>
#include "widget.h"
#include "ui_widget.h"
#include "tcpserver.h"
#include "tcpclient.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//UDP socket, 用于对话聊天
udpSocket = new QUdpSocket(this);
port = 45454;
udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
sendMessage(NewParticipant);
//TCP socket, 用于文件传输
server = new TcpServer(this);
connect(server, SIGNAL(sendFileName(QString)), this, SLOT(getFileName(QString)));
//字体格式自动切换显示
connect(ui ->messageTextEdit, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
this, SLOT(currentFormatChanged(const QTextCharFormat)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::newParticipant(QString userName, QString localHostName, QString ipAddress)
{
bool isEmpty = ui ->userTableWidget
->findItems(localHostName, Qt::MatchExactly).isEmpty();
qDebug("%s:%d, userName = %s, localHostName = %s, ipAddress = %s", __FUNCTION__, __LINE__,
qPrintable(userName), qPrintable(localHostName), qPrintable(ipAddress));
if(isEmpty)
{
QTableWidgetItem *user = new QTableWidgetItem(userName);
QTableWidgetItem *host = new QTableWidgetItem(localHostName);
QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
ui ->userTableWidget ->insertRow(0);
ui ->userTableWidget ->setItem(0, 0, user);
ui ->userTableWidget ->setItem(0, 1, host);
ui ->userTableWidget ->setItem(0, 2, ip);
ui ->messageBrower ->setTextColor(Qt::gray);
ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 10));
ui ->messageBrower ->append(tr("%1 在线!").arg(userName));
ui ->userNumLabel ->setText(tr("在线人数:%1")
.arg(ui ->userTableWidget ->rowCount()));
sendMessage(NewParticipant);
}
}
void Widget::participantLeft(QString userName, QString localHostName, QString time)
{
int rowNum = ui ->userTableWidget ->findItems(localHostName,
Qt::MatchExactly).first()->row();
ui ->userTableWidget ->removeRow(rowNum);
ui ->messageBrower ->setTextColor(Qt::gray);
ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 10));
ui ->messageBrower ->append(tr("%1 于 %2离开!").arg(userName).arg(time));
ui ->userNumLabel ->setText(tr("在线人数:%1")
.arg(ui ->userTableWidget ->rowCount()));
}
void Widget::sendMessage(MessageType type, QString serverAddress)
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIp();
out << type << getUserName() << localHostName;
switch (type)
{
case Message:
if(ui->messageTextEdit->toPlainText() == "")
{
QMessageBox::warning(0, tr("警告"),
tr("发送内容不能为空"), QMessageBox::Ok);
return;
}
out << address << getMessage();
ui -> messageBrower -> verticalScrollBar()
->setValue(ui->messageBrower->verticalScrollBar()->maximum());
break;
case NewParticipant:
out << address;
break;
case ParticipantLeft:
break;
case FileName:
{
int row = ui ->userTableWidget ->currentRow();
QString clientAddress = ui ->userTableWidget ->item(row, 2) ->text();
out << address << clientAddress << fileName;
break;
}
case Refuse:
out << serverAddress;
break;
default:
break;
}
qDebug("%s:%d, type = %d, userName = %s, localHostName = %s, ipAddress = %s",
__FUNCTION__,
__LINE__,
type,
getUserName().toStdString().data(),
localHostName.toStdString().data(),
address.toStdString().data());
udpSocket->writeDatagram(data, QHostAddress::Broadcast, port);
// udpSocket->flush();
// udpSocket ->waitForBytesWritten();
}
void Widget::closeEvent(QCloseEvent *event)
{
sendMessage(ParticipantLeft);
QWidget::closeEvent(event);
}
QString Widget::getIp()
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach(QHostAddress address, list)
{
//扎到IPV4地址,不是127开头的环回地址,并且不是169开头的地址:如果接到路由器的话,还有169.254.xx.xx的,169开头的是私有地址,没法使用
if(address.protocol() == QAbstractSocket::IPv4Protocol
&& !address.toString().startsWith("169")
&& !address.toString().startsWith("127"))
{
return address.toString();
}
}
return 0;
}
QString Widget::getUserName()
{
QStringList envVariables;
envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
<< "HOSTNAME.*" << "DOMAINNAME.*";
QStringList environment = QProcess::systemEnvironment();
foreach (QString string, envVariables)
{
int index = environment.indexOf(QRegExp(string));
if (index != -1)
{
QStringList stringList = environment.at(index).split('=');
if (stringList.size() == 2)
{
return stringList.at(1);
break;
}
}
}
return "unknown";
}
QString Widget::getMessage()
{
QString msg = ui ->messageTextEdit ->toHtml();
ui ->messageTextEdit ->clear();
ui ->messageTextEdit ->setFocus();
return msg;
}
bool Widget::saveFile(const QString &fileName)
{
QFile file(fileName);
if(!file.open(QFile::WriteOnly | QFile::Text))
{
QMessageBox::warning(this, tr("保存文件"),
tr("无法保存文件 %1 %2").arg(fileName)
.arg(file.errorString()));
return false;
}
QTextStream out(&file);
out << ui ->messageBrower ->toPlainText();
return true;
}
void Widget::hasPendingFile(QString userName, QString serverAddress, QString clientAddress, QString fileName)
{
QString ipAddress = getIp();
if(ipAddress == clientAddress)
{
int btn = QMessageBox::information(this,tr("接受文件"),
tr("来自%1(%2)的文件:%3,是否接收?")
.arg(userName).arg(serverAddress).arg(fileName),
QMessageBox::Yes,QMessageBox::No);
if (btn == QMessageBox::Yes) {
QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),fileName);
if(!name.isEmpty())
{
tcpClient *client = new tcpClient(this);
client->setFileName(name);
client->setHostAddress(QHostAddress(serverAddress));
client->show();
}
} else {
sendMessage(Refuse, serverAddress);
}
}
}
void Widget::processPendingDatagrams()
{
qDebug("%s:%d", __FUNCTION__, __LINE__);
while(udpSocket ->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket ->pendingDatagramSize());
udpSocket ->readDatagram(datagram.data(), datagram.size());
QDataStream in(&datagram, QIODevice::ReadOnly);
int messageType;
in >> messageType;
QString userName, localHostName, ipAddress, message;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
qDebug("%s:%d, type = %d", __FUNCTION__, __LINE__, messageType);
switch (messageType) {
case Message:
in >> userName >> localHostName >> ipAddress >> message;
ui ->messageBrower ->setTextColor(Qt::blue);
ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 12));
ui ->messageBrower ->append("[" + userName + "]" + time);
ui ->messageBrower ->append(message);
break;
case NewParticipant:
in >> userName >> localHostName >> ipAddress;
newParticipant(userName, localHostName, ipAddress);
break;
case ParticipantLeft:
in >> userName >> localHostName;
participantLeft(userName, localHostName, time);
break;
case FileName:
{
in >> userName >> localHostName >> ipAddress;
QString clientAddress, fileName;
in >> clientAddress >> fileName;
hasPendingFile(userName, ipAddress, clientAddress, fileName);
break;
}
case Refuse:
{
in >> userName >> localHostName;
QString serverAddress;
in >> serverAddress;
QString ipAddress = getIp();
if(ipAddress == serverAddress)
{
server ->refused();
}
break;
}
default:
break;
}
}
}
void Widget::on_sendButton_clicked()
{
sendMessage(Message);
}
void Widget::getFileName(QString name)
{
fileName = name;
sendMessage(FileName);
}
void Widget::on_sendToolBtn_clicked()
{
if(ui->userTableWidget ->selectedItems().isEmpty())
{
QMessageBox::warning(0, tr("选择用户"),
tr("请先从用户列表选择要传送的用户!"), QMessageBox::Ok);
return;
}
server ->show();
server ->initServer();
}
void Widget::on_fontComboBox_currentFontChanged(const QFont &f)
{
ui ->messageTextEdit ->setCurrentFont(f);
ui ->messageTextEdit ->setFocus();
}
void Widget::on_sizeComboBox_currentIndexChanged(const QString &arg1)
{
ui ->messageTextEdit ->setFontPointSize(arg1.toDouble());
ui ->messageTextEdit ->setFocus();
}
void Widget::on_boldToolBtn_clicked(bool checked)
{
if(checked)
{
ui ->messageTextEdit ->setFontWeight(QFont::Bold);
}
else
{
ui ->messageTextEdit ->setFontWeight(QFont::Normal);
}
ui ->messageTextEdit ->setFocus();
}
void Widget::on_italicToolBtn_clicked(bool checked)
{
ui ->messageTextEdit ->setFontItalic(checked);
ui ->messageTextEdit ->setFocus();
}
void Widget::on_underlineToolBtn_clicked(bool checked)
{
ui ->messageTextEdit ->setFontUnderline(checked);
ui ->messageTextEdit ->setFocus();
}
void Widget::on_colorToolBtn_clicked()
{
color = QColorDialog::getColor(color, this);
if(color.isValid())
{
ui ->messageTextEdit ->setTextColor(color);
ui ->messageTextEdit ->setFocus();
}
}
void Widget::currentFormatChanged(const QTextCharFormat &format)
{
ui ->fontComboBox ->setCurrentFont(format.font());
//如果字体大小出错(因为我们最小的字体为9),使用12
if(format.fontPointSize() < 9)
{
ui ->sizeComboBox ->setCurrentIndex(3);
}
else
{
ui ->sizeComboBox ->setCurrentIndex(ui ->sizeComboBox ->findText(QString::number(format.fontPointSize())));
}
ui ->boldToolBtn ->setChecked(format.font().bold());
ui ->italicToolBtn ->setChecked(format.font().italic());
ui ->underlineToolBtn ->setChecked(format.font().underline());
color = format.foreground().color();
}
void Widget::on_saveToolBtn_clicked()
{
if(ui ->messageBrower ->document() ->isEmpty())
{
QMessageBox::warning(0, tr("警告"),
tr("聊天记录为空,无法保存!"), QMessageBox::Ok);
}
else
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("保存聊天记录"), tr("聊天记录"), tr("文本(*.txt);;All File(*.*"));
if(!fileName.isEmpty())
{
saveFile(fileName);
}
}
}
void Widget::on_clearToolBtn_clicked()
{
ui ->messageBrower ->clear();
}
void Widget::on_exitButton_clicked()
{
close();
}
4.tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <QTime>
#include <QDialog>
#include <QFile>
#include <QTcpServer>
#include <QTcpSocket>
namespace Ui {
class TcpServer;
}
class TcpServer : public QDialog
{
Q_OBJECT
public:
explicit TcpServer(QWidget *parent = nullptr);
~TcpServer();
void initServer();
void refused();
protected:
void closeEvent(QCloseEvent *);
private slots:
void on_serverOpenBtn_clicked();
void on_serverSendBtn_clicked();
void on_serverCloseBtn_clicked();
void sendMessage();
void updateClientProgress(qint64 numBytes);
signals:
void sendFileName(QString fileName);
private:
Ui::TcpServer *ui;
qint16 tcpPort;
QTcpServer *tcpServer;
QTcpSocket *clientConnection;
QString fileName;
QString theFileName;
QFile *localFile;
qint64 payloadSize;
qint64 totalBytes;
qint64 bytesWritten;
qint64 bytesToWrite;
QByteArray outBlock; //缓存一次发送的数据
QTime time; //定时器
};
#endif // TCPSERVER_H
5.tcpserver.cpp
#include "tcpserver.h"
#include "ui_tcpserver.h"
#include <QFileDialog>
#include <QMessageBox>
TcpServer::TcpServer(QWidget *parent) :
QDialog(parent),
ui(new Ui::TcpServer)
{
ui->setupUi(this);
setFixedSize(350, 180);
tcpPort = 6666;
tcpServer = new QTcpServer(this);
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendMessage()));
initServer();
}
TcpServer::~TcpServer()
{
delete ui;
}
void TcpServer::initServer()
{
payloadSize = 64 * 1024;
totalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
ui ->serverStatusLabel ->setText(tr("请选择要传送的文件"));
ui ->progressBar ->reset();
ui ->serverOpenBtn ->setEnabled(true);
ui ->serverSendBtn ->setEnabled(false);
tcpServer ->close();
}
void TcpServer::refused()
{
tcpServer ->close();
ui ->serverStatusLabel ->setText(tr("对方拒绝接收!!!"));
}
void TcpServer::closeEvent(QCloseEvent *)
{
on_serverCloseBtn_clicked();
}
//打开按钮
void TcpServer::on_serverOpenBtn_clicked()
{
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
{
theFileName = fileName.right(fileName.size() - fileName.lastIndexOf("/")-1);
ui ->serverStatusLabel ->setText(tr("要传送的文件为:%1").arg(theFileName));
ui ->serverSendBtn ->setEnabled(true);
ui ->serverOpenBtn ->setEnabled(true);
}
}
//发送按钮
void TcpServer::on_serverSendBtn_clicked()
{
if(!tcpServer ->listen(QHostAddress::Any, tcpPort))
{
qDebug() << tcpServer ->errorString();
close();
return;
}
ui ->serverStatusLabel ->setText(tr("等待对方接收......"));
emit sendFileName(theFileName);
}
void TcpServer::on_serverCloseBtn_clicked()
{
if(tcpServer ->isListening())
{
tcpServer ->close();
if(localFile ->isOpen())
{
localFile ->close();
}
clientConnection ->abort();
}
close();
}
void TcpServer::sendMessage()
{
ui ->serverSendBtn ->setEnabled(false);
clientConnection = tcpServer ->nextPendingConnection();
connect(clientConnection, SIGNAL(bytesWritten(qint64)),
this, SLOT(updateClientProgress(qint64)));
ui ->serverStatusLabel ->setText(tr("开始传送文件 %1!").arg(theFileName));
localFile = new QFile(fileName);
if(!localFile ->open(QFile::ReadOnly))
{
QMessageBox::warning(this, tr("应用程序"), tr("无法读取文件 %1:\n%@").arg(fileName).arg(localFile->errorString()));
return;
}
totalBytes = localFile ->size();
QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_5_9);
time.start(); //开始计时
QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf("/") -1);
sendOut <<qint64(0) << qint64(0) << currentFile;
totalBytes += outBlock.size();
sendOut.device() ->seek(0);
sendOut << totalBytes << qint64(outBlock.size() - sizeof(qint64)*2);
bytesToWrite = totalBytes - clientConnection ->write(outBlock);
outBlock.resize(0);
}
void TcpServer::updateClientProgress(qint64 numBytes)
{
bytesWritten += (int)numBytes;
if(bytesToWrite > 0){
outBlock = localFile->read(qMin(bytesToWrite,payloadSize));
bytesToWrite -= (int)clientConnection->write(outBlock);
outBlock.resize(0);
}
else{
localFile->close();
}
ui->progressBar->setMaximum(totalBytes);
ui->progressBar->setValue(bytesWritten);
float useTime = time.elapsed();
double speed = bytesWritten / useTime;
ui->serverStatusLabel->setText(tr("已发送 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
.arg(bytesWritten / (1024*1024))//已发送
.arg(speed*1000/(1024*1024),0,'f',2)//速度
.arg(totalBytes / (1024 * 1024))//总大小
.arg(useTime/1000,0,'f',0)//用时
.arg(totalBytes/speed/1000 - useTime/1000,0,'f',0));//剩余时间
//num.sprintf("%.1f KB/s", (bytesWritten*1000) / (1024.0*time.elapsed()));
if(bytesWritten == totalBytes)
ui->serverStatusLabel->setText(tr("传送文件 %1 成功").arg(theFileName));
}
6.tcpclient.h
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QTime>
namespace Ui {
class tcpClient;
}
class tcpClient : public QDialog
{
Q_OBJECT
public:
explicit tcpClient(QWidget *parent = nullptr);
~tcpClient();
void setHostAddress(QHostAddress address);
void setFileName(QString fileName);
protected:
void closeEvent(QCloseEvent *);
private:
Ui::tcpClient *ui;
QTcpSocket *tcpclient;
quint16 tcpPort;
quint16 blockSize;
QHostAddress hostAddress;
qint64 TotalBytes;
qint64 bytesReceived;
qint64 bytesToReceive;
qint64 fileNameSize;
QString fileName;
QFile *localFile;
QByteArray inBlock;
QTime time;
private slots:
void on_tcpClientCancelBtn_clicked();
void on_tcpClientCloseBtn_clicked();
void newConnect();
void readMessage();
void displayError(QAbstractSocket::SocketError socketError);
};
#endif // TCPCLIENT_H
7.tcpclient.cpp
#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QMessageBox>
tcpClient::tcpClient(QWidget *parent) :
QDialog(parent),
ui(new Ui::tcpClient)
{
ui->setupUi(this);
setFixedSize(350, 180);
TotalBytes = 0;
bytesReceived = 0;
fileNameSize = 0;
tcpclient = new QTcpSocket(this);
tcpPort = 6666;
connect(tcpclient, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(tcpclient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}
tcpClient::~tcpClient()
{
delete ui;
}
void tcpClient::setHostAddress(QHostAddress address)
{
hostAddress = address;
newConnect();
}
void tcpClient::setFileName(QString fileName)
{
localFile = new QFile(fileName);
}
void tcpClient::closeEvent(QCloseEvent *)
{
on_tcpClientCloseBtn_clicked();
}
void tcpClient::newConnect()
{
blockSize = 0;
tcpclient ->abort();
tcpclient ->connectToHost(hostAddress, tcpPort);
time.start();
}
void tcpClient::readMessage()
{
QDataStream in(tcpclient);
in.setVersion(QDataStream::Qt_4_7);
float useTime = time.elapsed();
if (bytesReceived <= sizeof(qint64)*2) {
if ((tcpclient->bytesAvailable()
>= sizeof(qint64)*2) && (fileNameSize == 0))
{
in>>TotalBytes>>fileNameSize;
bytesReceived += sizeof(qint64)*2;
}
if((tcpclient->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)){
in>>fileName;
bytesReceived +=fileNameSize;
if(!localFile->open(QFile::WriteOnly))
{
QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.")
.arg(fileName).arg(localFile->errorString()));
return;
}
}
else
{
return;
}
}
if (bytesReceived < TotalBytes) {
bytesReceived += tcpclient->bytesAvailable();
inBlock = tcpclient->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
ui->progressBar->setMaximum(TotalBytes);
ui->progressBar->setValue(bytesReceived);
double speed = bytesReceived / useTime;
ui->tcpClientStatusLabel->setText(tr("已接收 %1MB (%2MB/s) "
"\n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
.arg(bytesReceived / (1024*1024))
.arg(speed*1000/(1024*1024),0,'f',2)
.arg(TotalBytes / (1024 * 1024))
.arg(useTime/1000,0,'f',0)
.arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));
if(bytesReceived == TotalBytes)
{
localFile->close();
tcpclient->close();
ui->tcpClientStatusLabel->setText(tr("接收文件 %1 完毕")
.arg(fileName));
}
}
void tcpClient::displayError(QAbstractSocket::SocketError socketError)
{
switch (socketError) {
case QAbstractSocket::RemoteHostClosedError:
break;
default:
qDebug() << tcpclient ->errorString();
}
}
void tcpClient::on_tcpClientCancelBtn_clicked()
{
tcpclient ->abort();
if(localFile ->isOpen())
{
localFile ->close();
}
}
void tcpClient::on_tcpClientCloseBtn_clicked()
{
tcpclient ->abort();
if(localFile ->isOpen())
{
localFile ->close();
}
close();
}
注意事项:
1.确保本地只有一个网卡启用,要不然会获取到很多IP地址;如果电脑连接到路由器的话,你有可能会获取到169开头的IP地址:169.254.xx.xx, 169开头的是私有地址,没法使用,以下是获取本地IP地址的代码
QString Widget::getIp()
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach(QHostAddress address, list)
{
//扎到IPV4地址,不是127开头的环回地址,并且不是169开头的地址:如果接到路由器的话,还有169.254.xx.xx的,169开头的是私有地址,没法使用
if(address.protocol() == QAbstractSocket::IPv4Protocol
&& !address.toString().startsWith("169")
&& !address.toString().startsWith("127"))
{
return address.toString();
}
}
return 0;
}
源码下载
https://download.csdn.net/download/guoyunfei123/12261023
————————————————
版权声明:本文为CSDN博主「tiankong19999」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guoyunfei123/article/details/105014590
参考《Qt及Qt Quick开发实战精解》,该书介绍的很详细,不做过多介绍。
末尾有源码下载地址
1.main.cpp
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
2.widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QTextCharFormat>
class QUdpSocket;
class TcpServer;
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
//枚举变量信息类型:消息、新用户加入、用户退出、文件名、拒绝接收文件
enum MessageType
{
Message,
NewParticipant,
ParticipantLeft,
FileName,
Refuse
};
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
protected:
void newParticipant(QString userName, QString localHostName, QString ipAddress);
void participantLeft(QString userName, QString localHostName, QString time);
void sendMessage(MessageType type, QString serverAddress="");
void closeEvent(QCloseEvent *event);
QString getIp();
QString getUserName();
QString getMessage();
bool saveFile(const QString &fileName);
void hasPendingFile(QString userName, QString serverAddress,
QString clientAddress, QString fileName);
private:
Ui::Widget *ui;
QUdpSocket *udpSocket;
quint16 port;
QString fileName;
TcpServer *server;
QColor color;
private slots:
void processPendingDatagrams();
void on_sendButton_clicked();
void getFileName(QString name);
void on_sendToolBtn_clicked();
void on_fontComboBox_currentFontChanged(const QFont &f);
void on_sizeComboBox_currentIndexChanged(const QString &arg1);
void on_boldToolBtn_clicked(bool checked);
void on_italicToolBtn_clicked(bool checked);
void on_underlineToolBtn_clicked(bool checked);
void on_colorToolBtn_clicked();
void currentFormatChanged(const QTextCharFormat &format);
void on_saveToolBtn_clicked();
void on_clearToolBtn_clicked();
void on_exitButton_clicked();
};
#endif // WIDGET_H
3.widget.cpp
#include <QUdpSocket>
#include <QHostInfo>
#include <QMessageBox>
#include <QScrollBar>
#include <QDateTime>
#include <QNetworkInterface>
#include <QProcess>
#include <QDebug>
#include <QFileDialog>
#include <QColorDialog>
#include <QThread>
#include "widget.h"
#include "ui_widget.h"
#include "tcpserver.h"
#include "tcpclient.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
//UDP socket, 用于对话聊天
udpSocket = new QUdpSocket(this);
port = 45454;
udpSocket->bind(port, QUdpSocket::ShareAddress | QUdpSocket::ReuseAddressHint);
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(processPendingDatagrams()));
sendMessage(NewParticipant);
//TCP socket, 用于文件传输
server = new TcpServer(this);
connect(server, SIGNAL(sendFileName(QString)), this, SLOT(getFileName(QString)));
//字体格式自动切换显示
connect(ui ->messageTextEdit, SIGNAL(currentCharFormatChanged(QTextCharFormat)),
this, SLOT(currentFormatChanged(const QTextCharFormat)));
}
Widget::~Widget()
{
delete ui;
}
void Widget::newParticipant(QString userName, QString localHostName, QString ipAddress)
{
bool isEmpty = ui ->userTableWidget
->findItems(localHostName, Qt::MatchExactly).isEmpty();
qDebug("%s:%d, userName = %s, localHostName = %s, ipAddress = %s", __FUNCTION__, __LINE__,
qPrintable(userName), qPrintable(localHostName), qPrintable(ipAddress));
if(isEmpty)
{
QTableWidgetItem *user = new QTableWidgetItem(userName);
QTableWidgetItem *host = new QTableWidgetItem(localHostName);
QTableWidgetItem *ip = new QTableWidgetItem(ipAddress);
ui ->userTableWidget ->insertRow(0);
ui ->userTableWidget ->setItem(0, 0, user);
ui ->userTableWidget ->setItem(0, 1, host);
ui ->userTableWidget ->setItem(0, 2, ip);
ui ->messageBrower ->setTextColor(Qt::gray);
ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 10));
ui ->messageBrower ->append(tr("%1 在线!").arg(userName));
ui ->userNumLabel ->setText(tr("在线人数:%1")
.arg(ui ->userTableWidget ->rowCount()));
sendMessage(NewParticipant);
}
}
void Widget::participantLeft(QString userName, QString localHostName, QString time)
{
int rowNum = ui ->userTableWidget ->findItems(localHostName,
Qt::MatchExactly).first()->row();
ui ->userTableWidget ->removeRow(rowNum);
ui ->messageBrower ->setTextColor(Qt::gray);
ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 10));
ui ->messageBrower ->append(tr("%1 于 %2离开!").arg(userName).arg(time));
ui ->userNumLabel ->setText(tr("在线人数:%1")
.arg(ui ->userTableWidget ->rowCount()));
}
void Widget::sendMessage(MessageType type, QString serverAddress)
{
QByteArray data;
QDataStream out(&data, QIODevice::WriteOnly);
QString localHostName = QHostInfo::localHostName();
QString address = getIp();
out << type << getUserName() << localHostName;
switch (type)
{
case Message:
if(ui->messageTextEdit->toPlainText() == "")
{
QMessageBox::warning(0, tr("警告"),
tr("发送内容不能为空"), QMessageBox::Ok);
return;
}
out << address << getMessage();
ui -> messageBrower -> verticalScrollBar()
->setValue(ui->messageBrower->verticalScrollBar()->maximum());
break;
case NewParticipant:
out << address;
break;
case ParticipantLeft:
break;
case FileName:
{
int row = ui ->userTableWidget ->currentRow();
QString clientAddress = ui ->userTableWidget ->item(row, 2) ->text();
out << address << clientAddress << fileName;
break;
}
case Refuse:
out << serverAddress;
break;
default:
break;
}
qDebug("%s:%d, type = %d, userName = %s, localHostName = %s, ipAddress = %s",
__FUNCTION__,
__LINE__,
type,
getUserName().toStdString().data(),
localHostName.toStdString().data(),
address.toStdString().data());
udpSocket->writeDatagram(data, QHostAddress::Broadcast, port);
// udpSocket->flush();
// udpSocket ->waitForBytesWritten();
}
void Widget::closeEvent(QCloseEvent *event)
{
sendMessage(ParticipantLeft);
QWidget::closeEvent(event);
}
QString Widget::getIp()
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach(QHostAddress address, list)
{
//扎到IPV4地址,不是127开头的环回地址,并且不是169开头的地址:如果接到路由器的话,还有169.254.xx.xx的,169开头的是私有地址,没法使用
if(address.protocol() == QAbstractSocket::IPv4Protocol
&& !address.toString().startsWith("169")
&& !address.toString().startsWith("127"))
{
return address.toString();
}
}
return 0;
}
QString Widget::getUserName()
{
QStringList envVariables;
envVariables << "USERNAME.*" << "USER.*" << "USERDOMAIN.*"
<< "HOSTNAME.*" << "DOMAINNAME.*";
QStringList environment = QProcess::systemEnvironment();
foreach (QString string, envVariables)
{
int index = environment.indexOf(QRegExp(string));
if (index != -1)
{
QStringList stringList = environment.at(index).split('=');
if (stringList.size() == 2)
{
return stringList.at(1);
break;
}
}
}
return "unknown";
}
QString Widget::getMessage()
{
QString msg = ui ->messageTextEdit ->toHtml();
ui ->messageTextEdit ->clear();
ui ->messageTextEdit ->setFocus();
return msg;
}
bool Widget::saveFile(const QString &fileName)
{
QFile file(fileName);
if(!file.open(QFile::WriteOnly | QFile::Text))
{
QMessageBox::warning(this, tr("保存文件"),
tr("无法保存文件 %1 %2").arg(fileName)
.arg(file.errorString()));
return false;
}
QTextStream out(&file);
out << ui ->messageBrower ->toPlainText();
return true;
}
void Widget::hasPendingFile(QString userName, QString serverAddress, QString clientAddress, QString fileName)
{
QString ipAddress = getIp();
if(ipAddress == clientAddress)
{
int btn = QMessageBox::information(this,tr("接受文件"),
tr("来自%1(%2)的文件:%3,是否接收?")
.arg(userName).arg(serverAddress).arg(fileName),
QMessageBox::Yes,QMessageBox::No);
if (btn == QMessageBox::Yes) {
QString name = QFileDialog::getSaveFileName(0,tr("保存文件"),fileName);
if(!name.isEmpty())
{
tcpClient *client = new tcpClient(this);
client->setFileName(name);
client->setHostAddress(QHostAddress(serverAddress));
client->show();
}
} else {
sendMessage(Refuse, serverAddress);
}
}
}
void Widget::processPendingDatagrams()
{
qDebug("%s:%d", __FUNCTION__, __LINE__);
while(udpSocket ->hasPendingDatagrams())
{
QByteArray datagram;
datagram.resize(udpSocket ->pendingDatagramSize());
udpSocket ->readDatagram(datagram.data(), datagram.size());
QDataStream in(&datagram, QIODevice::ReadOnly);
int messageType;
in >> messageType;
QString userName, localHostName, ipAddress, message;
QString time = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
qDebug("%s:%d, type = %d", __FUNCTION__, __LINE__, messageType);
switch (messageType) {
case Message:
in >> userName >> localHostName >> ipAddress >> message;
ui ->messageBrower ->setTextColor(Qt::blue);
ui ->messageBrower ->setCurrentFont(QFont("Times New Roman", 12));
ui ->messageBrower ->append("[" + userName + "]" + time);
ui ->messageBrower ->append(message);
break;
case NewParticipant:
in >> userName >> localHostName >> ipAddress;
newParticipant(userName, localHostName, ipAddress);
break;
case ParticipantLeft:
in >> userName >> localHostName;
participantLeft(userName, localHostName, time);
break;
case FileName:
{
in >> userName >> localHostName >> ipAddress;
QString clientAddress, fileName;
in >> clientAddress >> fileName;
hasPendingFile(userName, ipAddress, clientAddress, fileName);
break;
}
case Refuse:
{
in >> userName >> localHostName;
QString serverAddress;
in >> serverAddress;
QString ipAddress = getIp();
if(ipAddress == serverAddress)
{
server ->refused();
}
break;
}
default:
break;
}
}
}
void Widget::on_sendButton_clicked()
{
sendMessage(Message);
}
void Widget::getFileName(QString name)
{
fileName = name;
sendMessage(FileName);
}
void Widget::on_sendToolBtn_clicked()
{
if(ui->userTableWidget ->selectedItems().isEmpty())
{
QMessageBox::warning(0, tr("选择用户"),
tr("请先从用户列表选择要传送的用户!"), QMessageBox::Ok);
return;
}
server ->show();
server ->initServer();
}
void Widget::on_fontComboBox_currentFontChanged(const QFont &f)
{
ui ->messageTextEdit ->setCurrentFont(f);
ui ->messageTextEdit ->setFocus();
}
void Widget::on_sizeComboBox_currentIndexChanged(const QString &arg1)
{
ui ->messageTextEdit ->setFontPointSize(arg1.toDouble());
ui ->messageTextEdit ->setFocus();
}
void Widget::on_boldToolBtn_clicked(bool checked)
{
if(checked)
{
ui ->messageTextEdit ->setFontWeight(QFont::Bold);
}
else
{
ui ->messageTextEdit ->setFontWeight(QFont::Normal);
}
ui ->messageTextEdit ->setFocus();
}
void Widget::on_italicToolBtn_clicked(bool checked)
{
ui ->messageTextEdit ->setFontItalic(checked);
ui ->messageTextEdit ->setFocus();
}
void Widget::on_underlineToolBtn_clicked(bool checked)
{
ui ->messageTextEdit ->setFontUnderline(checked);
ui ->messageTextEdit ->setFocus();
}
void Widget::on_colorToolBtn_clicked()
{
color = QColorDialog::getColor(color, this);
if(color.isValid())
{
ui ->messageTextEdit ->setTextColor(color);
ui ->messageTextEdit ->setFocus();
}
}
void Widget::currentFormatChanged(const QTextCharFormat &format)
{
ui ->fontComboBox ->setCurrentFont(format.font());
//如果字体大小出错(因为我们最小的字体为9),使用12
if(format.fontPointSize() < 9)
{
ui ->sizeComboBox ->setCurrentIndex(3);
}
else
{
ui ->sizeComboBox ->setCurrentIndex(ui ->sizeComboBox ->findText(QString::number(format.fontPointSize())));
}
ui ->boldToolBtn ->setChecked(format.font().bold());
ui ->italicToolBtn ->setChecked(format.font().italic());
ui ->underlineToolBtn ->setChecked(format.font().underline());
color = format.foreground().color();
}
void Widget::on_saveToolBtn_clicked()
{
if(ui ->messageBrower ->document() ->isEmpty())
{
QMessageBox::warning(0, tr("警告"),
tr("聊天记录为空,无法保存!"), QMessageBox::Ok);
}
else
{
QString fileName = QFileDialog::getSaveFileName(this,
tr("保存聊天记录"), tr("聊天记录"), tr("文本(*.txt);;All File(*.*"));
if(!fileName.isEmpty())
{
saveFile(fileName);
}
}
}
void Widget::on_clearToolBtn_clicked()
{
ui ->messageBrower ->clear();
}
void Widget::on_exitButton_clicked()
{
close();
}
4.tcpserver.h
#ifndef TCPSERVER_H
#define TCPSERVER_H
#include <QTime>
#include <QDialog>
#include <QFile>
#include <QTcpServer>
#include <QTcpSocket>
namespace Ui {
class TcpServer;
}
class TcpServer : public QDialog
{
Q_OBJECT
public:
explicit TcpServer(QWidget *parent = nullptr);
~TcpServer();
void initServer();
void refused();
protected:
void closeEvent(QCloseEvent *);
private slots:
void on_serverOpenBtn_clicked();
void on_serverSendBtn_clicked();
void on_serverCloseBtn_clicked();
void sendMessage();
void updateClientProgress(qint64 numBytes);
signals:
void sendFileName(QString fileName);
private:
Ui::TcpServer *ui;
qint16 tcpPort;
QTcpServer *tcpServer;
QTcpSocket *clientConnection;
QString fileName;
QString theFileName;
QFile *localFile;
qint64 payloadSize;
qint64 totalBytes;
qint64 bytesWritten;
qint64 bytesToWrite;
QByteArray outBlock; //缓存一次发送的数据
QTime time; //定时器
};
#endif // TCPSERVER_H
5.tcpserver.cpp
#include "tcpserver.h"
#include "ui_tcpserver.h"
#include <QFileDialog>
#include <QMessageBox>
TcpServer::TcpServer(QWidget *parent) :
QDialog(parent),
ui(new Ui::TcpServer)
{
ui->setupUi(this);
setFixedSize(350, 180);
tcpPort = 6666;
tcpServer = new QTcpServer(this);
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(sendMessage()));
initServer();
}
TcpServer::~TcpServer()
{
delete ui;
}
void TcpServer::initServer()
{
payloadSize = 64 * 1024;
totalBytes = 0;
bytesWritten = 0;
bytesToWrite = 0;
ui ->serverStatusLabel ->setText(tr("请选择要传送的文件"));
ui ->progressBar ->reset();
ui ->serverOpenBtn ->setEnabled(true);
ui ->serverSendBtn ->setEnabled(false);
tcpServer ->close();
}
void TcpServer::refused()
{
tcpServer ->close();
ui ->serverStatusLabel ->setText(tr("对方拒绝接收!!!"));
}
void TcpServer::closeEvent(QCloseEvent *)
{
on_serverCloseBtn_clicked();
}
//打开按钮
void TcpServer::on_serverOpenBtn_clicked()
{
fileName = QFileDialog::getOpenFileName(this);
if(!fileName.isEmpty())
{
theFileName = fileName.right(fileName.size() - fileName.lastIndexOf("/")-1);
ui ->serverStatusLabel ->setText(tr("要传送的文件为:%1").arg(theFileName));
ui ->serverSendBtn ->setEnabled(true);
ui ->serverOpenBtn ->setEnabled(true);
}
}
//发送按钮
void TcpServer::on_serverSendBtn_clicked()
{
if(!tcpServer ->listen(QHostAddress::Any, tcpPort))
{
qDebug() << tcpServer ->errorString();
close();
return;
}
ui ->serverStatusLabel ->setText(tr("等待对方接收......"));
emit sendFileName(theFileName);
}
void TcpServer::on_serverCloseBtn_clicked()
{
if(tcpServer ->isListening())
{
tcpServer ->close();
if(localFile ->isOpen())
{
localFile ->close();
}
clientConnection ->abort();
}
close();
}
void TcpServer::sendMessage()
{
ui ->serverSendBtn ->setEnabled(false);
clientConnection = tcpServer ->nextPendingConnection();
connect(clientConnection, SIGNAL(bytesWritten(qint64)),
this, SLOT(updateClientProgress(qint64)));
ui ->serverStatusLabel ->setText(tr("开始传送文件 %1!").arg(theFileName));
localFile = new QFile(fileName);
if(!localFile ->open(QFile::ReadOnly))
{
QMessageBox::warning(this, tr("应用程序"), tr("无法读取文件 %1:\n%@").arg(fileName).arg(localFile->errorString()));
return;
}
totalBytes = localFile ->size();
QDataStream sendOut(&outBlock, QIODevice::WriteOnly);
sendOut.setVersion(QDataStream::Qt_5_9);
time.start(); //开始计时
QString currentFile = fileName.right(fileName.size() - fileName.lastIndexOf("/") -1);
sendOut <<qint64(0) << qint64(0) << currentFile;
totalBytes += outBlock.size();
sendOut.device() ->seek(0);
sendOut << totalBytes << qint64(outBlock.size() - sizeof(qint64)*2);
bytesToWrite = totalBytes - clientConnection ->write(outBlock);
outBlock.resize(0);
}
void TcpServer::updateClientProgress(qint64 numBytes)
{
bytesWritten += (int)numBytes;
if(bytesToWrite > 0){
outBlock = localFile->read(qMin(bytesToWrite,payloadSize));
bytesToWrite -= (int)clientConnection->write(outBlock);
outBlock.resize(0);
}
else{
localFile->close();
}
ui->progressBar->setMaximum(totalBytes);
ui->progressBar->setValue(bytesWritten);
float useTime = time.elapsed();
double speed = bytesWritten / useTime;
ui->serverStatusLabel->setText(tr("已发送 %1MB (%2MB/s) \n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
.arg(bytesWritten / (1024*1024))//已发送
.arg(speed*1000/(1024*1024),0,'f',2)//速度
.arg(totalBytes / (1024 * 1024))//总大小
.arg(useTime/1000,0,'f',0)//用时
.arg(totalBytes/speed/1000 - useTime/1000,0,'f',0));//剩余时间
//num.sprintf("%.1f KB/s", (bytesWritten*1000) / (1024.0*time.elapsed()));
if(bytesWritten == totalBytes)
ui->serverStatusLabel->setText(tr("传送文件 %1 成功").arg(theFileName));
}
6.tcpclient.h
#ifndef TCPCLIENT_H
#define TCPCLIENT_H
#include <QDialog>
#include <QTcpSocket>
#include <QHostAddress>
#include <QFile>
#include <QTime>
namespace Ui {
class tcpClient;
}
class tcpClient : public QDialog
{
Q_OBJECT
public:
explicit tcpClient(QWidget *parent = nullptr);
~tcpClient();
void setHostAddress(QHostAddress address);
void setFileName(QString fileName);
protected:
void closeEvent(QCloseEvent *);
private:
Ui::tcpClient *ui;
QTcpSocket *tcpclient;
quint16 tcpPort;
quint16 blockSize;
QHostAddress hostAddress;
qint64 TotalBytes;
qint64 bytesReceived;
qint64 bytesToReceive;
qint64 fileNameSize;
QString fileName;
QFile *localFile;
QByteArray inBlock;
QTime time;
private slots:
void on_tcpClientCancelBtn_clicked();
void on_tcpClientCloseBtn_clicked();
void newConnect();
void readMessage();
void displayError(QAbstractSocket::SocketError socketError);
};
#endif // TCPCLIENT_H
7.tcpclient.cpp
#include "tcpclient.h"
#include "ui_tcpclient.h"
#include <QMessageBox>
tcpClient::tcpClient(QWidget *parent) :
QDialog(parent),
ui(new Ui::tcpClient)
{
ui->setupUi(this);
setFixedSize(350, 180);
TotalBytes = 0;
bytesReceived = 0;
fileNameSize = 0;
tcpclient = new QTcpSocket(this);
tcpPort = 6666;
connect(tcpclient, SIGNAL(readyRead()), this, SLOT(readMessage()));
connect(tcpclient, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(displayError(QAbstractSocket::SocketError)));
}
tcpClient::~tcpClient()
{
delete ui;
}
void tcpClient::setHostAddress(QHostAddress address)
{
hostAddress = address;
newConnect();
}
void tcpClient::setFileName(QString fileName)
{
localFile = new QFile(fileName);
}
void tcpClient::closeEvent(QCloseEvent *)
{
on_tcpClientCloseBtn_clicked();
}
void tcpClient::newConnect()
{
blockSize = 0;
tcpclient ->abort();
tcpclient ->connectToHost(hostAddress, tcpPort);
time.start();
}
void tcpClient::readMessage()
{
QDataStream in(tcpclient);
in.setVersion(QDataStream::Qt_4_7);
float useTime = time.elapsed();
if (bytesReceived <= sizeof(qint64)*2) {
if ((tcpclient->bytesAvailable()
>= sizeof(qint64)*2) && (fileNameSize == 0))
{
in>>TotalBytes>>fileNameSize;
bytesReceived += sizeof(qint64)*2;
}
if((tcpclient->bytesAvailable() >= fileNameSize) && (fileNameSize != 0)){
in>>fileName;
bytesReceived +=fileNameSize;
if(!localFile->open(QFile::WriteOnly))
{
QMessageBox::warning(this,tr("应用程序"),tr("无法读取文件 %1:\n%2.")
.arg(fileName).arg(localFile->errorString()));
return;
}
}
else
{
return;
}
}
if (bytesReceived < TotalBytes) {
bytesReceived += tcpclient->bytesAvailable();
inBlock = tcpclient->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
ui->progressBar->setMaximum(TotalBytes);
ui->progressBar->setValue(bytesReceived);
double speed = bytesReceived / useTime;
ui->tcpClientStatusLabel->setText(tr("已接收 %1MB (%2MB/s) "
"\n共%3MB 已用时:%4秒\n估计剩余时间:%5秒")
.arg(bytesReceived / (1024*1024))
.arg(speed*1000/(1024*1024),0,'f',2)
.arg(TotalBytes / (1024 * 1024))
.arg(useTime/1000,0,'f',0)
.arg(TotalBytes/speed/1000 - useTime/1000,0,'f',0));
if(bytesReceived == TotalBytes)
{
localFile->close();
tcpclient->close();
ui->tcpClientStatusLabel->setText(tr("接收文件 %1 完毕")
.arg(fileName));
}
}
void tcpClient::displayError(QAbstractSocket::SocketError socketError)
{
switch (socketError) {
case QAbstractSocket::RemoteHostClosedError:
break;
default:
qDebug() << tcpclient ->errorString();
}
}
void tcpClient::on_tcpClientCancelBtn_clicked()
{
tcpclient ->abort();
if(localFile ->isOpen())
{
localFile ->close();
}
}
void tcpClient::on_tcpClientCloseBtn_clicked()
{
tcpclient ->abort();
if(localFile ->isOpen())
{
localFile ->close();
}
close();
}
注意事项:
1.确保本地只有一个网卡启用,要不然会获取到很多IP地址;如果电脑连接到路由器的话,你有可能会获取到169开头的IP地址:169.254.xx.xx, 169开头的是私有地址,没法使用,以下是获取本地IP地址的代码
QString Widget::getIp()
{
QList<QHostAddress> list = QNetworkInterface::allAddresses();
foreach(QHostAddress address, list)
{
//扎到IPV4地址,不是127开头的环回地址,并且不是169开头的地址:如果接到路由器的话,还有169.254.xx.xx的,169开头的是私有地址,没法使用
if(address.protocol() == QAbstractSocket::IPv4Protocol
&& !address.toString().startsWith("169")
&& !address.toString().startsWith("127"))
{
return address.toString();
}
}
return 0;
}
源码下载
https://download.csdn.net/download/guoyunfei123/12261023
————————————————
版权声明:本文为CSDN博主「tiankong19999」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/guoyunfei123/article/details/105014590
标签:Widget,QT,void,局域网,聊天工具,ui,QString,fileName,include 来源: https://www.cnblogs.com/managechina/p/16635127.html