1.server.h
#ifndef SERVER_H
#define SERVER_H
#include <QMainWindow>
#include<QLabel>
#include<QtNetwork/QHostInfo>
#include<QtNetwork/QTcpServer>
#include<QtNetwork/QTcpSocket>
#include<QFile>
namespace Ui {
class Server;
}
class Server : public QMainWindow
{
Q_OBJECT
private:
QLabel *LabListen;
QLabel *LabSocketState;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QString getlocalIP();
private: //file
QTcpServer *fileServer;
QTcpSocket *fileSocket;
qint64 totalBytes;
qint64 bytesReceived;
qint64 bytestoWrite;
qint64 bytesWritten;
qint64 filenameSize;
QString filename;
QString m_imgDirPath;
///每次发送数据大小
qint64 perDataSize;
QFile *localFile;
本地缓冲区
QByteArray inBlock;
QByteArray outBlock;
void initSocket();
void initFileSocket();
private slots:
void onNewConnection();
void onSocketStateChange(QAbstractSocket::SocketState socketState);
void onClientConnected();
void onClientDisconnected();
void onSocketReadyRead();
void acceptFileConnection();
void updateFileProgress();
void displayError(QAbstractSocket::SocketError socketError);
void updateFileProgress(qint64);
//void on_openImgButton_clicked(); //浏览按钮-点击槽函数
void on_imgListWidget_clicked(const QModelIndex &index); //图片列表-点击槽函数
protected:
void closeEvent(QCloseEvent *event);
private slots:
void on_acHostInfo_triggered();
void on_actStart_triggered();
void on_actStop_triggered();
void on_btnSendMsg_clicked();
void on_btnSaveDir_clicked();
void on_btnSelectFile_clicked();
void on_btnSendFile_clicked();
void Auto_get_mac_IP();
void on_choose_image_pushButton_clicked();
void on_closeimage_pushButton_clicked();
void on_actClear_triggered();
public:
explicit Server(QWidget *parent = 0);
~Server();
//QMediaPlayer *player1,*player2;
private:
Ui::Server *ui;
};
#endif // SERVER_H
2、main.c
#include "server.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Server w;
w.show();
return a.exec();
}
3、server.cpp
#include "server.h"
#include "ui_server.h"
#include<QFileDialog>
#include <QMessageBox>
#include <QMainWindow>
#include <QMovie>
#include <QDebug>
#include <QDateTime>
#include <QSettings>
#include <qnetworkinterface.h>
QString Server::getlocalIP()
{
QString hostName=QHostInfo::localHostName();
QHostInfo hostInfo=QHostInfo::fromName(hostName);
QList<QHostAddress> addList=hostInfo.addresses();
if(!addList.isEmpty())
for(int i=0;i<addList.count();i++)
{
QHostAddress localIP =addList.at(i);
if(localIP.protocol()==QAbstractSocket::IPv4Protocol)
return localIP.toString();
}
return "";
}
Server::Server(QWidget *parent) :QMainWindow(parent), ui(new Ui::Server)
{
ui->setupUi(this);
this->setWindowTitle("Tcp Server");
initSocket();
initFileSocket();
Auto_get_mac_IP();
//设置指定背景色
ui->image_label->setStyleSheet("background-color:rgb(222, 222, 222);");//图片显示区域颜色
ui->imgListWidget->setStyleSheet("background-color:rgb(222, 222, 222);");//接收名字区域设置
ui->plainTextEdit->setStyleSheet("background-color:rgb(222, 222, 222);");//信息显示区域背景颜色
ui->fg_label->setStyleSheet("QLabel{background-color:rgb(143, 0, 0);}");//信息提示去颜色
ui->fg_label->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");
ui->img_label->setStyleSheet("QLabel{background-color:rgb(143, 0, 0);}");//信息提示去颜色
ui->img_label->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");
ui->information_prompt_area_laber->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");
ui->Picture_display_area_label->setStyleSheet("background-color:rgb(143, 0, 0);font-size:18px;color:white");//图片显示区域背景颜色
}
void Server::Auto_get_mac_IP()//放到自动程序中,开机获取本机地址
{
//通过QNetworkInterface类来获取本机的IP地址和网络接口信息。
QList<QNetworkInterface> list = QNetworkInterface::allInterfaces();//获取所有网络接口的列表
//获取所有网络接口的列表
foreach(QNetworkInterface interface,list)
{ //遍历每一个网络接口
qDebug() << "Device: "<<interface.name(); //设备名
//硬件地址
qDebug() << "HardwareAddress: "<<interface.hardwareAddress();
/**********************************************************************************************/
/*
* ubuntu下获取ip地址 start
*/
/**********************************************************************************************/
if(interface.name()=="enp2s0"|interface.name()=="ethernet_32774")//我的ubuntu端口是enp2s0,windosethernet_32774 是你的需要根据自己的来判断
{
QList<QNetworkAddressEntry> entryList = interface.addressEntries();
//获取IP地址条目列表,每个条目中包含一个IP地址,一个子网掩码和一个广播地址
foreach(QNetworkAddressEntry entry,entryList)
{//遍历每一个IP地址条目
if( entry.ip().toString().size() < 16)//区分IPV6和IPV4
{
qDebug()<<"IP Address: "<<entry.ip().toString();
//IP地址
qDebug()<<"Netmask: " <<entry.netmask().toString();
//子网掩码
qDebug()<<"Broadcast: "<<entry.broadcast().toString();
//广播地址
ui->editIP->clear();//
ui->editIP->setText(QString (entry.ip().toString()));
}
}
}
/**********************************************************************************************/
/*
* ubuntu下获取ip地址 end
*/
/**********************************************************************************************/
}
}
void Server::on_acHostInfo_triggered()
{
Auto_get_mac_IP();//按键 再次刷新ip地址
}
void Server::initSocket()
{
LabListen=new QLabel("监听状态:");
LabListen->setMinimumWidth(150);
ui->statusBar->addWidget(LabListen);
LabSocketState=new QLabel("Socket状态:");//
LabSocketState->setMinimumWidth(200);
ui->statusBar->addWidget(LabSocketState);
tcpServer=new QTcpServer(this);
connect(tcpServer,SIGNAL(newConnection()),this,SLOT(onNewConnection()));
}
void Server::initFileSocket()
{
文件传送相关变量初始化
perDataSize = 64*1024;
totalBytes = 0;
bytestoWrite = 0;
bytesWritten = 0;
bytesReceived = 0;
filenameSize = 0;
///文件传送套接字
fileSocket = new QTcpSocket(this);
fileServer = new QTcpServer(this);
quint16 port=ui->spinPort->value()+1;//端口
qDebug()<<"initFileSocket"<<port;
fileServer->listen(QHostAddress::Any,ui->spinPort->value()+1);
connect(fileServer,SIGNAL(newConnection()),this,SLOT(acceptFileConnection()));
}
Server::~Server()
{
delete ui;
delete tcpServer;
delete fileServer;
}
void Server::on_actStart_triggered()
{
//从界面上读取ip和端口
const QString address_IP=ui->editIP->text();//IP地址
quint16 port=ui->spinPort->value();//端口
//可以使用 QHostAddress::Any 监听所有地址的对应端口
const QHostAddress address=(address_IP=="Any")?QHostAddress::Any:QHostAddress(address_IP);
tcpServer->listen(address,port);//
tcpServer->listen(QHostAddress::LocalHost,port);
ui->plainTextEdit->appendPlainText("**开始监听...");
ui->plainTextEdit->appendPlainText("**服务器地址:"+tcpServer->serverAddress().toString());
ui->plainTextEdit->appendPlainText("**服务器端口:"+QString::number(tcpServer->serverPort()));
ui->actStart->setEnabled(false);
ui->actStop->setEnabled(true);
LabListen->setText("监听状态:正在监听");
}
void Server::on_actStop_triggered()
{//停止监听
if (tcpServer->isListening()) //tcpServer正在监听
{
tcpServer->close();//停止监听
ui->actStart->setEnabled(true);
ui->actStop->setEnabled(false);
LabListen->setText("监听状态:已停止监听");
}
}
void Server::onNewConnection()
{
ui->plainTextEdit->appendPlainText("有新连接");
tcpSocket = tcpServer->nextPendingConnection(); //创建socket
connect(tcpSocket, SIGNAL(connected()),this, SLOT(onClientConnected()));//
connect(tcpSocket, SIGNAL(disconnected()), this, SLOT(onClientDisconnected()));
connect(tcpSocket,SIGNAL(stateChanged(QAbstractSocket::SocketState)),
this,SLOT(onSocketStateChange(QAbstractSocket::SocketState)));
onSocketStateChange(tcpSocket->state());
//连接信号与槽
connect(tcpSocket,SIGNAL(readyRead()),this,SLOT(onSocketReadyRead()));
qDebug()<<"Client connected success.";
}
void Server::onSocketStateChange(QAbstractSocket::SocketState socketState)
{//socket状态变化时
switch(socketState)
{
case QAbstractSocket::UnconnectedState:
LabSocketState->setText("scoket状态:UnconnectedState");
break;
case QAbstractSocket::HostLookupState:
LabSocketState->setText("scoket状态:HostLookupState");
break;
case QAbstractSocket::ConnectingState:
LabSocketState->setText("scoket状态:ConnectingState");
break;
case QAbstractSocket::ConnectedState:
LabSocketState->setText("scoket状态:ConnectedState");
break;
case QAbstractSocket::BoundState:
LabSocketState->setText("scoket状态:BoundState");
break;
case QAbstractSocket::ClosingState:
LabSocketState->setText("scoket状态:ClosingState");
break;
case QAbstractSocket::ListeningState:
LabSocketState->setText("scoket状态:ListeningState");
}
}
void Server::onClientConnected()
{//客户端接入时
ui->plainTextEdit->appendPlainText("**client socket connected");
ui->plainTextEdit->appendPlainText("**peer address:"+tcpSocket->peerAddress().toString());
ui->plainTextEdit->appendPlainText("**peer port:"+QString::number(tcpSocket->peerPort()));
}
void Server::onClientDisconnected()
{//客户端断开连接时
ui->plainTextEdit->appendPlainText("**client socket disconnected");
tcpSocket->deleteLater();
// deleteLater();
}
void Server::onSocketReadyRead()
{
ui->plainTextEdit->appendPlainText("[in] "+tcpSocket->readAll());
// ui->image_label->setPixmap(QPixmap(QString::fromLocal8Bit("E:\QT\TCP_Client_Server\\1.png"))); // 在imgLabel标签上显示图片
// ui->image_label->setScaledContents(true);
// ui->image_label->show();
}
void Server::on_btnSendMsg_clicked()
{
QString msg=ui->editMsg->text();
ui->plainTextEdit->appendPlainText("[out] "+msg);
ui->editMsg->clear();
ui->editMsg->setFocus();
QByteArray str=msg.toUtf8();
//str.append('\n');//添加一个换行符
tcpSocket->write(str);
}
void Server::closeEvent(QCloseEvent *event)
{//关闭窗口时停止监听
if (tcpServer->isListening())
tcpServer->close();//停止网络监听
if (fileServer->isListening())
fileServer->close();//停止网络监听
event->accept();
}
void Server::acceptFileConnection()
{
bytesWritten = 0;
///每次发送数据大小为64kb
perDataSize = 64*1024;
fileSocket =fileServer->nextPendingConnection();
///接受文件
readyRead()当网络套接字上有新的网络数据有效负载时
connect(fileSocket,SIGNAL(readyRead()),this,SLOT(updateFileProgress()));
connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
处理异常
connect(fileSocket,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(displayError(QAbstractSocket::SocketError)));
}
/**
* 接收文件进度
* @brief Server::updateFileProgress
*/
void Server::updateFileProgress()
{
QDataStream inFile(fileSocket);
inFile.setVersion(QDataStream::Qt_5_6);
ui->plainTextEdit->appendPlainText("updateFileProgress");
///如果接收到的数据小于16个字节,保存到来的文件头结构
if(bytesReceived <= sizeof(qint64)*2)
{
QByteArray bytes = NULL;
while(this->fileSocket->waitForReadyRead(100))
{
qDebug()<<"Data receiving...";
bytes.append(this->fileSocket->readAll());
}
//Send Back Data to Client
if(this->fileSocket->isWritable())
{
//结尾中的'\n'表示数据发送完毕
// QString sendData = "ok\n" ;
// QByteArray strs=sendData.toUtf8();
// this->fileSocket->write(strs);
}
else
{
qDebug()<<"Cannot send back data to Client.";
}
QPixmap pixmap;
pixmap.loadFromData(bytes);
//显示到GUI中
int with = ui->image_label->width();
int height = ui->image_label->height();
//QPixmap fitpixmap = pixmap.scaled(with, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 饱满填充
QPixmap fitpixmap = pixmap.scaled(with, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); // 按比例缩放
//ui->image_label->setScaledContents(false); //根据label大小缩放图片
ui->image_label->setPixmap(fitpixmap);
//时间保存文件名
QDateTime datetime;
QString timestr = datetime.currentDateTime().toString("yyyyMMddHHmmss");
//保存路径
filename = ui->editSaveDir->text()+"/"+timestr+".png";
qDebug()<<"filename"<<filename;
localFile = new QFile(filename);
if(!localFile->open(QFile::WriteOnly))
{
ui->plainTextEdit->appendPlainText("Server::open file error!");
return;
}
//保存文件
localFile->write(bytes);
bytes.resize(0);
}
///如果接收到的数据小于16个字节,保存到来的文件头结构
if(bytesReceived <= sizeof(qint64)*2)
{
if((fileSocket->bytesAvailable()>=(sizeof(qint64))*2) && (filenameSize==0))
{
接收数据总大小信息和文件名大小信息
inFile>>totalBytes>>filenameSize;
bytesReceived += sizeof(qint64)*2;
qDebug()<<"filenameSize success."<< filenameSize;
}
if((fileSocket->bytesAvailable()>=filenameSize) && (filenameSize != 0))
{
inFile>>filename;
bytesReceived += filenameSize;
接收的文件放在指定目录下
filename = ui->editSaveDir->text()+"/"+filename;
localFile = new QFile(filename);
if(!localFile->open(QFile::WriteOnly))
{
ui->plainTextEdit->appendPlainText("Server::open file error!");
return;
}
}
else
return;
}
/如果接收的数据小于总数据,则写入文件
if(bytesReceived < totalBytes)
{
bytesReceived += fileSocket->bytesAvailable();
inBlock = fileSocket->readAll();
localFile->write(inBlock);
inBlock.resize(0);
}
更新进度条显示
this->ui->progressBarRec->setMaximum(totalBytes);
this->ui->progressBarRec->setValue(bytesReceived);
数据接收完成时
if(bytesReceived == totalBytes)
{
this->ui->plainTextEdit->appendPlainText("Receive file successfully!");
bytesReceived = 0;
totalBytes = 0;
filenameSize = 0;
localFile->close();
//fileSocket->close();
}
}
void Server::updateFileProgress(qint64 numBytes)
{ 已经发送的数据大小
bytesWritten += (int)numBytes;
如果已经发送了数据
if(bytestoWrite > 0)
{
outBlock = localFile->read(qMin(bytestoWrite,perDataSize));
///发送完一次数据后还剩余数据的大小
bytestoWrite -= ((int)fileSocket->write(outBlock));
///清空发送缓冲区
outBlock.resize(0);
}
else
localFile->close();
更新进度条
this->ui->progressBarSend->setMaximum(totalBytes);
this->ui->progressBarSend->setValue(bytesWritten);
如果发送完毕
qDebug()<<"bytesWritten"<<bytesWritten<<"--"<<"totalBytes"<<totalBytes;
if(bytesWritten == totalBytes)
{
bytesWritten=0;totalBytes=0;
localFile->close();
// fileSocket->close();
qDebug()<<ui->progressBarRec->value()<<"value";
qDebug()<<ui->progressBarRec->maximum()<<"maximum";
}
}
/**
* @brief Server::getImage base64 转图片
* @param data
* @return
*/
//QImage Server::getImage(const QString &data)
//{
// QByteArray imageData = QByteArray::fromBase64(data.toLatin1());
// QImage image;
// image.loadFromData(imageData);
// return image;
//}
void Server::displayError(QAbstractSocket::SocketError socketError)
{
ui->plainTextEdit->appendPlainText(fileSocket->errorString());
//socket->close();
}
void Server::on_btnSaveDir_clicked()
{
ui->editSaveDir->setText(QFileDialog::getExistingDirectory(this,"请选择保存路径"));
}
void Server::on_btnSelectFile_clicked()
{
// ui->editFile->setText(QFileDialog::getOpenFileName(this,"请选择待发送文件"));
//???fileSocket->open(QIODevice::WriteOnly);
///文件传送进度更新
//connect(fileSocket,SIGNAL(bytesWritten(qint64)),this,SLOT(updateFileProgress(qint64)));
filename = QFileDialog::getOpenFileName(this,"Open a file");
ui->editFile->setText(filename);
}
void Server::on_btnSendFile_clicked()
{
localFile = new QFile(filename);
if(!localFile->open(QFile::ReadOnly))
{
ui->plainTextEdit->appendPlainText("Client:open file error!");
return;
}
///获取文件大小
this->totalBytes = localFile->size();
QDataStream sendout(&outBlock,QIODevice::WriteOnly);
sendout.setVersion(QDataStream::Qt_4_8);
QString currentFileName = filename.right(filename.size()-filename.lastIndexOf('/')-1);
qDebug()<<sizeof(currentFileName);
保留总代大小信息空间、文件名大小信息空间、文件名
sendout<<qint64(0)<<qint64(0)<<currentFileName;
totalBytes += outBlock.size();
sendout.device()->seek(0);
sendout<<totalBytes<<qint64((outBlock.size()-sizeof(qint64)*2));
bytestoWrite = totalBytes-fileSocket->write(outBlock);
outBlock.resize(0);
}
/*
void MainWindow::on_openImgButton_clicked()
{
//m_imgDirPath = QFileDialog::getExistingDirectory(this); // 获取图片所在目录的具体路径
m_imgDirPath=ui->lineEdit->text();
QDir dir(m_imgDirPath);
QFileInfoList fileInfoList = dir.entryInfoList(QDir::Files); // 获取目录下的文件
QString filePath; // 保存图片图片的绝对路径
// 在QListWidget中列出目录下的文件
for(int i=0; i<fileInfoList.count(); i++)
{
filePath.clear(); //清除上一次图片路径内容
filePath.append(m_imgDirPath + "/" + fileInfoList.at(i).fileName()); // 获得图片文件的绝对路径
if(fileInfoList.at(i).fileName() == "." || fileInfoList.at(i).fileName() == "..") // 跳过这两个隐藏目录
{
continue;
}
QListWidgetItem *item = new QListWidgetItem(QIcon(filePath), fileInfoList.at(i).fileName()); // 建立图片缩小图标
ui->imgListWidget->addItem(item); // 把图片缩小图标和名称显示在列表窗口中
}
}
*/
void Server::on_choose_image_pushButton_clicked()
{
/* QString filename;
QPixmap image_label;
filename=QFileDialog::getOpenFileName(this,tr("选择图像"),"",tr("Images (*.png *.bmp *.jpg *.tif *.GIF )"));//可打开的文件类型
if(!filename.isEmpty())
{
QImage image(filename);
ui->image_label->setPixmap(image_label.fromImage(image));// ui->image_label就是label的控件名字
ui->image_label->setScaledContents(true);
ui->image_label->show();
}
*/
m_imgDirPath=ui->editSaveDir->text();
QString filter;
QDir dir(m_imgDirPath);
QFileInfoList fileInfoList = dir.entryInfoList(); // 获取目录下的文件
QString filePath; // 保存图片图片的绝对路径
foreach(QFileInfo fileinfo, fileInfoList )filter = fileinfo.suffix(); //后缀名
// 在QListWidget中列出目录下的文件
for(int i=0; i<fileInfoList.count(); i++)
{
filePath.clear(); //清除上一次图片路径内容
filePath.append(m_imgDirPath + "/" + fileInfoList.at(i).fileName()); // 获得图片文件的绝对路径
if(fileInfoList.at(i).fileName() == "." || fileInfoList.at(i).fileName() == "..") // 跳过这两个隐藏目录
{
continue;
}
QListWidgetItem *item = new QListWidgetItem(QIcon(filePath), fileInfoList.at(i).fileName()); // 建立图片缩小图标
ui->imgListWidget->addItem(item); // 把图片缩小图标和名称显示在列表窗口中
}
ui->img_label->setText("图片加载完成");
}
//图片列表-点击槽函数
void Server::on_imgListWidget_clicked(const QModelIndex &index)
{
Q_UNUSED(index);
QString imgPath = (m_imgDirPath + "/" + ui->imgListWidget->currentItem()->text());
if(imgPath.endsWith(".gif") || imgPath.endsWith(".Gif")) //判断是否是gif动图
{
QMovie *movie =new QMovie(imgPath);
ui->image_label->setMovie(movie);
movie->start();
}
else
{
//显示图片
int with = ui->image_label->width();
int height = ui->image_label->height();
//QPixmap fitpixmap = pixmap.scaled(with, height, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); // 饱满填充
QPixmap fitpixmap = QPixmap(imgPath).scaled(with, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); // 按比例缩放
//ui->image_label->setScaledContents(false); //根据label大小缩放图片
ui->image_label->setPixmap(fitpixmap);
// ui->image_label->setPixmap(QPixmap(imgPath)); // 在imgLabel标签上显示图片
// ui->image_label->setScaledContents(true); //根据label大小缩放图片
}
}
void Server::on_closeimage_pushButton_clicked()
{
ui->image_label->clear();
ui->imgListWidget->clear();
ui->img_label->setText("请加载图片");
}
void Server::on_actClear_triggered()
{
ui->plainTextEdit->clear();
}