文件传输程序设计

一个简单的文件传输程序

文件是一种数据存储的形式,因此文件的传输实质上就是数据的传输。在这个程序中主要步骤为
1.发送方(这里暂定为服务端)首先打开文件将文件数据读入应用程序的发送缓冲区,然后调用send()函数发送给接收方(这里暂定为客户端)。
2.接收方调用recv()函数接收数据,并将接收到的数据写入文件.

程序中会用到的一些技术

1.文件位置的表示

在C/C++程序中,文件路径通常是一个由盘符、文件夹名、子文件夹名和文件名组成的字符串,各项之间用反斜线"“隔开。
比如 D:\C++程序\test\readme.txt 在程序代码中的文件路径应该表示成如下形式:
D:\C++程序\test\readme.txt
但是程序在运行时键盘输入的文件路径仍然是正常表示,即反斜线仍是其自身”"。
2.C++中的文件操作
①:C++中的文件处理功能是由输入文件流ifstream和输出文件流ofstream提供的,这两个流在头文件fstream中定义。
②:文件操作基本步骤
Ⅰ:在程序中包含头文件fstream
#include “fstream”
Ⅱ:定义文件流变量
ifstream inFile; //定义输入文件流对象
ofstream outFile; //定义输出文件流对象
Ⅲ:打开文件
inFile.open( filename, inmode);
outFile.open( filename, outmode);
inFile和outFile是第②中定义的流对象,filename是要打开的文件名,可以包含文件路径,inmode和outmode则是打开或建立文件的方式,该参数有默认值,可缺省。
Ⅳ:读写文件
对二进制文件使用get()方法可以从输入流中读取一个字符,put()方法则用于向输出流中写入一个字节
char ch1,ch2=’A’; //定义两个字符变量
inFile.get(ch1); //从输入文件流中读取一个字符存入变量ch1;
outFile.put(ch2); //将变量ch2种的一个字符写入输出文件流;
Ⅴ:关闭文件
inFile.close();
outFile.close();
3.获取文件长度的方法
接收端判断文件传输是否结束需要使用文件长度,但C/C++并不提供直接获取文件长度的函数。有很多方法可以获取文件长度,这里只介绍一种常用的简单方法。
这种方法的原理是基于这样一个事实,就是当文件的读写位置指针位于文件结束时,其值就等于文件长度。具体实现方法参见如下函数getfilesize()
long getfilesize(const char * filename)
{
ifstream inFile(filename); //定义流变量并打开文件
inFile.seekg(0, ios::end); //设置文件指针到文件流的尾部
streampos ps = inFile.tellg(); //读取文件指针的位置
inFile.close(); //关闭文件流
return ps;
}
4.文件信息结构体定义
发送文件名和文件长度所用的结构
struct fileMessage {
char fileName[256];
long int fileSize;
};
5.文件传输程序发送端和接收端的完整工作流程
文件传输流程

服务器端程序代码:

// Server.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <WinSock2.h>
using namespace std;

#pragma comment(lib, "Ws2_32.lib")
#define  PORT 1024

typedef struct fileMessage
{
	char fileName[26];
	long int filesize;
}fileMessage;


int main()
{
	SOCKET sock_server, newsock;
	struct sockaddr_in server_addr, client_addr; 
	char msg[] = { "Hello clinet" };
	// 初始化 winsock2.dll[12/27/2017 MagicScaring]
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);		//生成版本号
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		cout << "加载 winsock.dll失败" << endl;
		return 0;
	}
	// 创建套接字 [12/27/2017 MagicScaring]
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败! 错误代码:" << WSAGetLastError() << endl;
		WSACleanup();					//注销WinSock动态链接库
		return 0;
	}
	// 填写需要绑定的本地地址 [12/27/2017 MagicScaring]
	int addr_len = sizeof(struct sockaddr_in);
	memset((void*)&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	//server_addr.sin_addr.s_addr = inet_addr("192.168.5.38");

	if (bind(sock_server, (struct sockaddr*)&server_addr, addr_len) != 0)
	{
		cout << "绑定失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);				//关闭已连接套接字
		WSACleanup();							//注销WinSock动态链接库
		return 0;
	}

	// 开始监听 [12/27/2017 MagicScaring]
	if (listen(sock_server, 0) != 0)
	{
		cout << "listen调用失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	else
	{
		cout << "listening...." << endl;
	}
	// 开始发送文件 [1/2/2018 MagicScaring]
	char filename[500];
	cout << "请输入要传输的文件的路径" << endl;
	cin.getline(filename, 500);
	// 接收客户端连接请求 [1/2/2018 MagicScaring]
	if ((newsock = accept(sock_server, (struct sockaddr *)&client_addr, &addr_len)) == INVALID_SOCKET)
	{
		cout << "accept 函数调用失败! 错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	cout << "connect from " << inet_ntoa(client_addr.sin_addr) << endl;

	char OK[3], fileBuffer[1000];
	fileMessage fileMsg;
	int size = strlen(filename);
	
	
	while (filename[size] != '\\' && size > 0)
	{
		size--;
	}
	strcpy(fileMsg.fileName, filename + size + 1);

	ifstream inFile(filename, ios::in | ios::binary);

	if (!inFile.is_open())
	{
		cout << "Can not open " << filename << endl;
		closesocket(newsock);
		WSACleanup();
		return 0;
	}
	// 获取文件长度 [1/2/2018 MagicScaring]
	inFile.seekg(0, ios::end);
	size = inFile.tellg();
	inFile.seekg(0, ios::beg);
	
	fileMsg.filesize = htonl(size);
	send(newsock, (char*)&fileMsg, sizeof(fileMsg), 0);

	// 接收客户端发送来的OK信息 [1/2/2018 MagicScaring]
	if (recv(newsock, OK, sizeof(OK), 0) <= 0)
	{
		cout << "接收OK信息失败,程序退出" << endl;
		closesocket(sock_server);
		closesocket(newsock);
		WSACleanup();
		return 0;
	}
	// 发送文件内容 [1/2/2018 MagicScaring]
	if (strcmp(OK, "OK") == 0)
	{
		while (!inFile.eof())
		{
			inFile.read(fileBuffer, sizeof(fileBuffer));
			size = inFile.gcount();		//获取实际读取的字节数
			send(newsock, fileBuffer, size, 0);
		}
		cout << "file transfer finished" << endl;
		inFile.close();
	}
	else
	{
		cout << "对方无法接收文件" << endl;
	}

	closesocket(sock_server);
	closesocket(newsock);
	WSACleanup();
    return system("pause");
}


客户端程序代码:

// Client.cpp : Defines the entry point for the console application.
//

#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <fstream>
#include <WinSock2.h>
using namespace std;

#pragma comment(lib, "Ws2_32.lib")
#define  PORT 1024

typedef struct fileMessage
{
	char fileName[26];
	long int filesize;
}fileMessage;
#define  PORT 1024


int main()
{
	SOCKET sock_client;
	struct sockaddr_in server_addr, client_addr;
	int addr_len = sizeof(struct sockaddr_in);
	int name_len;
	char msgbuffer[1000];
	memset(msgbuffer, 0, sizeof(msgbuffer));
	// 初始化 winsock2.dll[12/27/2017 MagicScaring]
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);		//生成版本号
	if (WSAStartup(wVersionRequested, &wsaData) != 0)
	{
		cout << "加载 winsock.dll失败" << endl;
		return 0;
	}
	// 创建套接字 [12/27/2017 MagicScaring]
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR)
	{
		cout << "创建套接字失败! 错误代码:" << WSAGetLastError() << endl;
		WSACleanup();					//注销WinSock动态链接库
		return 0;
	}
	// 填写服务器地址 [12/27/2017 MagicScaring]
	char IP[20] = { "192.168.5.38" };
	/*char IP[20];
	cout << "输入服务器地址:" << endl;
	cin >> IP;*/
	memset((void*)&server_addr, 0, sizeof(server_addr));
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = inet_addr(IP);

	// 与服务器建立连接 [12/27/2017 MagicScaring]
	if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) == SOCKET_ERROR)
	{
		cout << "连接失败! 错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	fileMessage fileMsg;
	long int filelen = 0;
	char fileName[500] = "C:\\Users\\MagicScaring\\Desktop\\";
	char ok[3] = "OK";
	char fileBuffer[1000];
	_mkdir(fileName);

	if ((filelen = recv(sock_client, (char*)&fileMsg, sizeof(fileMsg), 0)) <= 0)
	{
		cout << "未接受到文件名字及文件长度" << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	filelen = ntohl(fileMsg.filesize);
	strcat(fileName, fileMsg.fileName);
	
	// 创建文件准备接收文件内容 [1/2/2018 MagicScaring]

	ofstream outFile(fileName, ios::out | ios::binary);
	if (!outFile.is_open())
	{
		cout << "Cannot open " << fileName << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	send(sock_client, ok, sizeof(ok), 0);

	// 接收文件数据并写入文件 [1/2/2018 MagicScaring]
	int size = 0;
	do 
	{
		size = recv(sock_client, fileBuffer, sizeof(fileBuffer), 0);
		outFile.write(fileBuffer, size);
		filelen -= size;
	} while (size != 0 && filelen > 0);

	cout << "Transfer finished" << endl;
	outFile.close();
	closesocket(sock_client);
	WSACleanup();
	
    return system("pause");
}


结果演示:

服务端
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CPe80uY9-1592977402618)(https://img-blog.csdn.net/20180103111243226?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvTWFnaWNTY2FyaW5n/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast)]

  • 4
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值