服务端
界面:
在pro文件中写上
QT += core gui network
CONFIG+=c++11
这是一些需要的头文件:
#include<QTcpServer>//监听套接字
#include<QTcpSocket>//通信套接字
#include<QFile>
#include<QTimer>
#include<QFileDialog>
#include<QDebug>
#include<QFileInfo>
定义一些变量
private:
Ui::ServerWidget *ui;
QTcpServer *tcpServer;
QTcpSocket *tcpSocket;
QFile file;
QString fileName;//文件名字
qint64 filesize;//文件大小
qint64 sendSize;//已经发送文件的大小
QTimer timer;//设置一个定时器
选择文件按钮的槽函数:
void ServerWidget::on_Choosebutton_clicked()
{
//获取打开文件的路径
QString path=QFileDialog::getOpenFileName(this,"open","../");
if(path.isEmpty()==false)
{
//选中文件以后准备打开文件
//获取文件信息
//初始化两个变量
fileName.clear();
filesize=0;
QFileInfo info(path);
fileName=info.fileName();//获取文件名字
filesize=info.size();//获取文件大小
sendSize=0;
//只读方式打开
//指定文件的名字
file.setFileName(path);
bool isopen=file.open(QIODevice::ReadOnly);
if(!isopen)
{
qDebug()<<"Open File Error!";
}
//提示打开什么文件
ui->textEdit->append(path);
ui->Choosebutton->setEnabled(false);//锁定选择文件按钮
ui->Sendbutton->setEnabled(true);//开启发送按钮
}
else
{
qDebug()<<"Wrong FilePath";
}
}
其中主要的内部方法就是:
1.QFileDialog::getOpenFileName(this,"open","../");用来打开文件,并且获取路径,这个是只能获取单个文件的路径
2.QFileInfo info(path); 创建这个对象来获取文件的信息
3.bool isopen=file.open(QIODevice::ReadOnly); 判断文件是不是打开成功
4.setEnabled( )可以开启按钮,也可以锁定按钮
发送文件按钮的函数:
void ServerWidget::on_Sendbutton_clicked()
{
//先发送文件头信息,格式:文件名##文件大小
QString head=QString("%1##%2").arg(fileName) .arg(filesize);
//发送头部信息
qint64 len = tcpSocket->write(head.toUtf8());
if(len>0)//头部信息发送成功
{
//发送真正文件信息
//为了放置TCP文件黏包
//定时器
timer.start(20);
}
else
{
qDebug()<<"The head of the file open wrong";
file.close();
ui->Choosebutton->setEnabled(true);
ui->Sendbutton->setEnabled(false);
}
}
主要函数:
1. tcpSocket->write(head.toUtf8()); write函数用来发送信息
构造函数:
ServerWidget::ServerWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ServerWidget)
{
ui->setupUi(this);
tcpServer=new QTcpServer(this);//开辟空间,指定父对象
//绑定监听
tcpServer->listen(QHostAddress::Any,8888);
setWindowTitle("服务器端口8888");
//刚开始两个按钮都不能按
ui->Sendbutton->setEnabled(false);
ui->Choosebutton->setEnabled(false);
//如果客户端成功链接服务器
//tcpServer会自动触发newConnect
connect(tcpServer,&QTcpServer::newConnection,
[=]()
{
//取出建立好链接的套接字
tcpSocket=tcpServer->nextPendingConnection();
//获取对方的ip和端口
QString ip=tcpSocket->peerAddress().toString();
quint16 port=tcpSocket->peerPort();
QString str=QString("[%1 %2] 成功链接").arg(ip).arg(port);
ui->textEdit->setText(str);//显示到编辑区
//成功链接后才能选择文件
ui->Sendbutton->setEnabled(true);
});
connect(&timer,&QTimer::timeout,
[=]()
{
//关闭定时器
timer.stop();
//发送文件
SendDate();
});
}
主要函数:
1.tcpServer->listen(QHostAddress::Any,8888); 用来绑定套接字与端口和IP
2.QTcpServer::newConnection 链接成功会自动触发这个信号、
3. tcpSocket=tcpServer->nextPendingConnection(); 取出套接字
4.tcpSocket->peerAddress().toString(); 取出ip
5.tcpSocket->peerPort(); 取出端口
6.QTimer::timeout 开启定时器后自动触发
发送信息函数SendDate():
void ServerWidget::SendDate()
{
qint64 len=0;
do
{
//每次发4k大小
char buffer[4*1024]={0};
len=0;
//往文件中读数据
len=tcpSocket->read(buffer,sizeof(buffer));
//往文件中写数据
len=tcpSocket->write(buffer,len);
//发送的数据需要累加
sendSize+=len;
}while(len>0);
//是否发送文件完毕
if(sendSize==filesize)
{
ui->textEdit->setText("文件发送完毕");
file.close();//关闭文件
//把客户端断开
tcpSocket->disconnectFromHost();
tcpSocket->close();
}
}
主要函数:
1.tcpSocket->read(buffer,sizeof(buffer)); 读文件
2.tcpSocket->write(buffer,len); 写文件
3.tcpSocket->disconnect(); 断开链接
4.tcpSocket->close(); 关闭套接字
客户端:
界面:
Connect按钮函数:
void ClienWidget::on_connectbutton_clicked()
{
//获取服务器的IP和端口
QString ip=ui->ipEdit->text();
quint16 port=ui->portEdit->text().toInt();
//开始链接
tcpSocket->connectToHost(QHostAddress(ip),port);
}
主要函数:
1.tcpSocket->connectToHost(QHostAddress(ip),port); 根据设定的IP和端口主动链接
构造函数:
ClienWidget::ClienWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::ClienWidget)
{
ui->setupUi(this);
tcpSocket=new QTcpSocket(this);
isStart=true;
connect(tcpSocket,&QTcpSocket::readyRead,
[=]()
{
//取出接受的内容
QByteArray arr=tcpSocket->readAll();
//要区分是头还是真的内容
if(isStart)
{
//接收头
isStart=false;
//解析头部信息buf="文件名##文件大小"
fileName=QString(arr).section("##",0,0);
filesize=QString(arr).section("##",1,1).toInt();
receSize=0;
//打开文件
file.setFileName(fileName);
bool isok=file.open(QIODevice::WriteOnly);
if(isok==false)
{
qDebug()<<"Open File Fail";
}
}
else//接受文件信息
{
qint64 len= file.write(arr);
receSize+=len;
if(receSize==filesize)
{
file.close();
QMessageBox::information(this,"完成","文件接受完成");
tcpSocket->disconnectFromHost();//断开链接
tcpSocket->close();
}
}
});
}
主要函数:
1.QTcpSocket::readyRead 一旦传输成功就会自动触发的信号
2.tcpSocket->readAll() 读取文件中的所有东西
3. section("##",0,0) 这个是用来拆解字符串信息的
因为我们的头信息是以“文件名字##文件大小”来显示的,所以这里用section("##",0,0) 表示取出以“##”分隔方式的第一段(0,0)表示第一段,也就是(1,1)表示第二段
4.QIODevice::WriteOnly 以只读的方式打开一个文件
5. QMessageBox::information(this,"完成","文件接受完成") 是弹出一个提醒框,具体参数参考手册