27Tcp文件传输
前面介绍了TCP和UDP的通信,只是文体通信,只能传送文字。本次介绍文件传输,也就是文件读写和TCP通信的结合。

解析:根据之前的TCP通信,建立彼此的连接。服务器选择文件,首先将文件的基本信息发送给客户端。如:文件名,文件大小(用于进度条使用)。如上显示,“head#hello#1024”,即头部信息,hello就是文件名,1024是文件大小。如此客户端可以在某个磁盘创建好文件,便于后面的写入。服务端每次读取MK大小的数据,每读取一次,传输一次,客户端写入一次但要累计发送文件的大小,便于与原文件大小比较。
黏包问题:
如果头部信息和文件内容重合或追加。比如”head#hello#1024abdjsjdas”,那么“abdjsjdas”本质是内容信息而不是头部。
解决方式:设定一个定时器,在发出头部信息后,间隔N毫秒后再发送内容信息。
服务端
FileServer.h
#ifndef FILESERVER_H
#define FILESERVER_H
#include <QWidget>
#include <QTcpServer>
#include <QTcpSocket>
#include <QFile>
#include <QFileDialog>
#include <QFileInfo>
#include <QTimer>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
void SendData();
~Widget();
private slots:
void on_pushButton_clicked(); //选择文件
void on_pushButton_2_clicked(); //发送文件
private:
Ui::Widget *ui;
QTcpServer *m_listenSock; //监听套接字
QTcpSocket *m_serverSock; //通信套接字
QFile m_file; //文件
QString m_strFileName; //文件名
qint64 m_fileSize; //文件大小
qint64 m_sendSize; //已发送的大小
QTimer timer; //定时器
};
#endif // FILESERVER_H
FileServer.cpp
#include "FileServer.h"
#include "ui_widget.h"
#include <QMessageBox>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
this->setWindowTitle("服务器端口:888");
//将选择文件和发送文件的灰度
m_listenSock=new QTcpServer(this);
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(false);
//监听
bool bIsOk=m_listenSock->listen(QHostAddress::Any,888);
if(bIsOk==true)
{
connect(m_listenSock,&QTcpServer::newConnection,
[=]()
{
//获取客户端的通信套接字
m_serverSock=m_listenSock->nextPendingConnection();
QString IP=m_serverSock->peerAddress().toString();
quint16 port=m_serverSock->peerPort();
QString strTemp=QString("[%1:%2]接入成功").arg(IP).arg(port);
ui->textEdit->setText(strTemp);
//激活选择文件按钮
ui->pushButton->setEnabled(true);
}
);
}
connect(&timer,&QTimer::timeout,
[=]()
{
//停止定时器,并开始发送文件内容
timer.stop();
SendData();
}
);
}
Widget::~Widget()
{
delete ui;
delete m_listenSock;
m_listenSock=NULL;
m_serverSock=NULL;
}
void Widget::on_pushButton_clicked()
{
QString strFilePath=QFileDialog::getOpenFileName(this,"Open","../");
if(strFilePath.isEmpty()==false)
{
//文件基本信息
QFileInfo info(strFilePath);
m_strFileName=info.fileName();
m_fileSize=info.size();
m_sendSize=0;
//qDebug()<<m_strFileName<<m_fileSize;
//指定文件名称
m_file.setFileName(strFilePath);
//打开文件
bool bIsOpen=m_file.open(QIODevice::ReadOnly);
if(bIsOpen==true)
{
ui->textEdit->append(strFilePath);
//激活发送文件按钮,灰度选择文件按钮
ui->pushButton->setEnabled(false);
ui->pushButton_2->setEnabled(true);
};
}
else
{
//打开失败
}
}
void Widget::on_pushButton_2_clicked()
{
//发送头部信息
QString strHead=QString("%1##%2")
.arg(m_strFileName)
.arg(m_fileSize);
qint64 len=m_serverSock->write(strHead.toUtf8());
//发送成功
if(len>0)
{
//防止黏包,头部信息和内容信息混淆
timer.start(1000);
}
else
{
//发送失败,重新选择文件
m_file.close();
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
}
}
void Widget::SendData()
{
qint64 len=0; //每次读取的大小
do
{
//每次读取、发送4K
char pBuf[4*1024]={0};
len=0;
//读多少,发送多少
len=m_file.read(pBuf,sizeof(pBuf));
m_serverSock->write(pBuf,len);
//累加发送了多少
m_sendSize+=len;
}while(len>0);
//len>0,表明有数据读取。0数据为空,<0读取失败。
if(m_fileSize==m_sendSize)
{
//QMessageBox::information(this,"提示","发送完成!");
ui->textEdit->append("发送完成!");
//激活选择文件按钮,灰度发送文件按钮
ui->pushButton->setEnabled(true);
ui->pushButton_2->setEnabled(false);
m_file.close();
//m_serverSock->disconnectFromHost();
//m_serverSock->close();
}
}
同一程序添加两个窗口,且有设计器。新建一个文件,但不是C++类文件,而是QT且带有界面类的,最后在main中使用show()直接显示。如下图:

client.h
#ifndef CLIENT_H
#define CLIENT_H
#include <QWidget>
#include <QTcpSocket>
#include <QFile>
#include <QProgressBar>
namespace Ui {
class Client;
}
class Client : public QWidget
{
Q_OBJECT
public:
explicit Client(QWidget *parent = 0);
~Client();
private slots:
void on_pushButton_clicked(); //请求连接
void on_pushButton_2_clicked(); //关闭连接
private:
Ui::Client *ui;
QTcpSocket *m_clientSock; //通信套接字
QProgressBar m_proBar; //进度条
QFile m_file; //文件
QString m_strFileName; //文件名
qint64 m_fileSize; //文件大小
qint64 m_recvSize; //已接收的大小
};
#endif // CLIENT_H
client.cpp
#include "client.h"
#include "ui_client.h"
#include <QMessageBox>
#include <QFileDialog>
Client::Client(QWidget *parent) :
QWidget(parent),
ui(new Ui::Client)
{
ui->setupUi(this);
this->setWindowTitle("客户端");
m_clientSock=new QTcpSocket(this);
//初始化进度条
ui->progressBar->setValue(0);
connect(m_clientSock,&QTcpSocket::connected,
[=]()
{
ui->textEdit->setText("连接成功!");
}
);
//判断文件头部信息还是内容信息
static bool bIsHead=true;
//通信
connect(m_clientSock,&QTcpSocket::readyRead,
[=]()
{
//获取服务器发来的内容
QByteArray byteBuf=m_clientSock->readAll();
//取出文件头部信息
if(bIsHead)
{
bIsHead=false;
//"filename##9999"
//解析头部信息
m_strFileName=QString(byteBuf).section("##",0,0);
m_fileSize=QString(byteBuf).section("##",1,1).toInt();
m_recvSize=0;
//根据文件的大小,设置进度条范围
ui->progressBar->setRange(0,m_fileSize/1024);
//m_strFileName="G:\\"+m_strFileName; //自拟文件路径
m_file.setFileName(m_strFileName); //默认源程序上一级目录
bool bIsOpen=m_file.open(QIODevice::WriteOnly);
if(bIsOpen==false)
{
//打开失败
}
}
//将读取的内容写入新文件
else
{
//写入文件
qint64 len=m_file.write(byteBuf);
m_recvSize+=len;
//更新进度条
ui->progressBar->setValue(m_recvSize/1024);
//接收完毕
if(m_recvSize==m_fileSize)
{
QMessageBox::information(this,"提示","接收完成!");
QString strTemp=QString("%1,接收完成").arg(m_strFileName);
ui->textEdit->append(strTemp);
ui->progressBar->setValue(0);
m_file.close();
//此处一定改,不然发下一文件失败,无法获取头部信息
bIsHead=true;
}
}
}
);
}
Client::~Client()
{
delete ui;
delete m_clientSock;
m_clientSock=NULL;
}
void Client::on_pushButton_clicked()
{
//设置对方的IP和端口
QString ip=ui->IP->text();
quint16 port=ui->Port->text().toInt();
//请求连接
m_clientSock->connectToHost(ip.toUtf8(),port);
}
void Client::on_pushButton_2_clicked()
{
//断开连接
m_clientSock->disconnectFromHost();
m_clientSock->close();
}
main.cpp
#include "FileServer.h"
#include <QApplication>
#include "client.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
Client c;
c.show();
return a.exec();
}
程序结果图:

27Tcp文件传输的更多相关文章
- Linux主机上实现树莓派的交叉编译及文件传输,远程登陆
0.环境 Linux主机OS:Ubuntu14.04 64位,运行在wmware workstation 10虚拟机 树莓派版本:raspberry pi 2 B型. 树莓派OS:官网下的的raspb ...
- putty提供的两个文件传输工具PSCP、PSFTP详细介绍
用 SSH 来传输文件 PuTTY 提供了两个文件传输工具 PSCP (PuTTY Secure Copy client) PSFTP (PuTTY SFTP client) PSCP 通过 SSH ...
- c# 局域网文件传输实例
一个基于c#的点对点局域网文件传输小案例,运行效果截图 //界面窗体 using System;using System.Collections.Generic;using System.Compon ...
- 使用 zssh 进行 Zmodem 文件传输
Zmodem 最早是设计用来在串行连接(uart.rs232.rs485)上进行数据传输的,比如,在 minicom 下,我们就可以方便的用 Zmodem (说 sz .rz 可能大家更熟悉)传输文件 ...
- 在windows 与Linux间实现文件传输(C++&C实现)
要实现windows与linux间的文件传输,可以通过socket网络编程来实现. 这次要实现的功能与<Windows下通过socket进行字符串和文件传输>中实现的功能相同,即客户端首先 ...
- Windows下通过socket进行字符串和文件传输
今天在windows平台下,通过socket实现了简单的文件传输.通过实现这一功能,了解基本的windows网络编程和相关函数的使用方法. 在windows平台上进行网络编程,首先都需要调用函数WSA ...
- Linux下几种文件传输命令 sz rz sftp scp
Linux下几种文件传输命令 sz rz sftp scp 最近在部署系统时接触了一些文件传输命令,分别做一下简单记录: 1.sftp Secure Ftp 是一个基于SSH安全协议的文件传输管理工具 ...
- 艺萌TCP文件传输及自动更新系统介绍(TCP文件传输)(四)
艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输) 该系统基于开源的networkComms通讯框架,此通讯框架以前是收费的,目前已经免费并开源,作者是英国的,开发时间5年多,框架很稳定. 项 ...
- 艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输)(一)
艺萌TCP文件上传下载及自动更新系统介绍(TCP文件传输) 该系统基于开源的networkComms通讯框架,此通讯框架以前是收费的,目前已经免费并开元,作者是英国的,开发时间5年多,框架很稳定. 项 ...
随机推荐
- Linux-Oracle
1.使用Oracle登录,或者其他用户登录,切换到Oracle账户下: 2.登录后在Oracle主目录后使用vi创建.bashrc文件: 3.在文件中输入如下参数: export ORACLE_SID ...
- jquery 添加可操作,编辑不可操作
--jsp <td class="queryTitle" width="100">优惠券批次号</td> <td class=&q ...
- vue2.0+element-ui(01简单点的单页面)
前言: 在<Vue.js权威指南>刚出版的时候,自己就作为一名前端粉捧了一把场,可是真是应了那句“出来混,总是要还的“这句话了,那时候信心满满的买来书想要认真研究,最终却还是把它搁浅了.直 ...
- centos solr4.5 tomcat 简单安装[已测试ok]
一.环境准备: 1.jdk安装 2.tomcat安装 这两个基本环境的安装在这里就不说了 二.下载solr-4.5.0.tgz 三.安装solr 1.解压solr tar -zxvf /opt/sol ...
- phpstrom配置
- iOS - UIImageView - how to handle UIImage image orientation
本文转载至 http://stackoverflow.com/questions/8915630/ios-uiimageview-how-to-handle-uiimage-image-orienta ...
- 安装Hadoop系列 — 安装SSH免密码登录
配置ssh免密码登录 1) 验证是否安装ssh:ssh -version显示如下的话则成功安装了OpenSSH_6.2p2 Ubuntu-6ubuntu0.1, OpenSSL 1.0.1e 11 ...
- 【BZOJ4423】[AMPPZ2013]Bytehattan 对偶图+并查集
[BZOJ4423][AMPPZ2013]Bytehattan Description 比特哈顿镇有n*n个格点,形成了一个网格图.一开始整张图是完整的.有k次操作,每次会删掉图中的一条边(u,v), ...
- js对字符串进行加密和解密方法!
在做一些微信小程序,或混合 app 的时候,或者是考虑到一些 JS 数据安全的问题.可能会使用到 JS 对用户信息进行缓存. 例如在开发:微信小程序对用户进行加密缓存,开发混合APP对用户信息进行加密 ...
- 【HTTP header】【Access-Control-Allow-Credentials】跨域Ajax请求时是否带Cookie的设置
1. 无关Cookie跨域Ajax请求 客户端 以 Jquery 的 ajax 为例: $.ajax({ url : 'http://remote.domain.com/corsrequest', d ...