TCP程序设计之简单的文件传输程序设计

任务

  设计服务端与客户端程序,从服务端输入要传送的文件路径,将文件传送给客户端,客户端接收文件并保存到指定位置。

服务端

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include "WinSock2.h"
#include "iostream"
#include "fstream"
#include "string.h"
#pragma comment(lib,"ws2_32.lib")  //链接WinSock导入库
#define PORT 65432
using namespace std;
struct fileMessage {
	char fileName[256];
	long int fileSize;
};
struct ArckMessage {
	char ok[3];
	unsigned long fileOffset;
};

int main(int argc, char **argv) {
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);   //调用2.2版本
	if (WSAStartup(wVersionRequested, &wsaData) != 0) {   //加载WinSock动态链接库
		cout << "加载WinSock DLL失败!\n";
		return 0;
	}

	SOCKET sock_server, newsock;   //监听套接字,已连接套接字
	struct sockaddr_in addr;       //填写绑定地址
	struct sockaddr_in client_addr;  //接收客户端发来的信息
	char msgbuffer[256];
	char msg[] = "Connect succeed.\n";  //发给客户端的信息

	//创建套接字
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) == SOCKET_ERROR) {
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}

	//填写要绑定的地址
	int addr_len = sizeof(struct sockaddr_in);
	memset((void*)&addr, 0, addr_len);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(PORT);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);   //允许本机的任何IP地址
	
	//给监听套接字绑定地址
	if (bind(sock_server, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
		cout << "地址绑定失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}

	//将套接字设为监听状态
	if (listen(sock_server, 5) != 0) {               //最多有5个连接请求在等待队列中
		cout << "listen函数调用失败!错误代码:" << WSAGetLastError() << endl;
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	else {
		cout << "listenning......\n";
	}

    //接收连接请求
	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 filename[500];
	cout << "输入要传输的文件路径:";
	cin.getline(filename, 500);
	char filebuffer[1000];
	struct fileMessage fileMsg;
	struct ArckMessage arkMsg;

	//从文件路径提取文件名,保存到变量filemsg中
	int size=strlen(filename);
	while (filename[size] != '\\'&&size > 0) {
		size--;
	}
	strcpy(fileMsg.fileName, filename + size);

	//打开要传输的文件
	ifstream inFile(filename, ios::in | ios::binary);
	if (!inFile.is_open()) {
		cout << "Cannot open " << filename << endl;
		closesocket(newsock);
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}

	//获取文件长度
	inFile.seekg(0, ios::end);   //将文件的位置指针移到文件末尾
	size = inFile.tellg();       //获取当前文件位置指针值,
	inFile.seekg(0, ios::beg);   //将文件的位置指针返回到文件头

	//发送文件名
	fileMsg.fileSize = htonl(size);   //将文件长度存入filemsg
	send(newsock, (char *)&fileMsg, sizeof(fileMsg), 0);  //发送filemsg
	if (recv(newsock, (char *)&arkMsg, sizeof(arkMsg), 0) <= 0) {
		cout << "接收失败\n";
		closesocket(newsock);
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	
	int pos = ntohl(arkMsg.fileOffset);
	inFile.seekg(0, ios::beg);   //将文件的位置指针移动到接收端请求位置

	//发送文件内容
	if (strcmp(arkMsg.ok, "ok") == 0) {
		while (!inFile.eof()) {
			inFile.read(filebuffer, sizeof(filebuffer));
			size = inFile.gcount();  //获取实际读取的字节数
			send(newsock, filebuffer, size, 0);
		}
		cout << "file transfer completed";
		inFile.close();
	}
	else
		cout << "无法接收文件!\n";

	closesocket(newsock);
	closesocket(sock_server);
	WSACleanup();
	return 0;
}

客户端

#define _WINSOCK_DEPRECATED_NO_WARNINGS
#define _CRT_SECURE_NO_WARNINGS
#include "WinSock2.h"
#include "iostream"
#include "fstream"
#include "string.h"
#include "direct.h"
#pragma comment(lib,"ws2_32.lib")  //链接WinSock导入库
#define PORT 65432
using namespace std;
struct fileMessage {
	char fileName[256];
	long int fileSize;
};
struct ArckMessage {
	char ok[3];
	unsigned long fileOffset;
};

int main(int argc, char **argv) {
	WSADATA wsaData;
	WORD wVersionRequested = MAKEWORD(2, 2);   //调用2.2版本
	if (WSAStartup(wVersionRequested, &wsaData) != 0) {   //加载WinSock动态链接库
		cout << "加载WinSock DLL失败!\n";
		return 0;
	}
	int sock_client;
	struct sockaddr_in server_addr;
	int addr_len = sizeof(struct sockaddr_in);

	//创建套接字
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
		cout << "创建套接字失败!错误代码:" << WSAGetLastError() << endl;
		WSACleanup();
		return 0;
	}

	//连接服务器
	memset((void *)&server_addr, 0, addr_len);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(PORT);
	server_addr.sin_addr.s_addr = inet_addr("127.0.0.1");
	if (connect(sock_client, (struct sockaddr *)&server_addr, addr_len) != 0) {
		cout << "连接失败!错误代码:" << WSAGetLastError();
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}

	//定义文件传输所需变量
	struct fileMessage fileMsg;
	long int filelen;
	char filename[500] = "D:\\download_test\\";   //指定接收到的文件的保存目录
	struct ArckMessage arkMsg = { "ok",0 };
	char fileBuffer[1000];
	
	_mkdir(filename);
	//接收文件名以及文件长度信息
	if ((filelen = recv(sock_client, (char *)&fileMsg, sizeof(fileMsg), 0)) <= 0) {
		cout << "未接收到文件名字以及长度!\n";
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	filelen = ntohl(fileMsg.fileSize);
	strcat(filename, fileMsg.fileName);

	//创建文件,准备接收文件内容
	ofstream outFile(filename, ios::out | ios::binary);
	if (!outFile.is_open()) {
		cout << "Cannot open " << filename << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}
	//将文件写位置移动至文件末尾,获取其值并发送
	outFile.seekp(0, ios::end);
	arkMsg.fileOffset = ntohl(outFile.tellp());
	send(sock_client, (char *)&arkMsg, sizeof(arkMsg), 0);  //发送文件及文件位置

	//接收文件数据并写入文件
	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 completed!\n";
	outFile.close();
	closesocket(sock_client);
	WSACleanup();
	return 0;
}

运行结果

发布了37 篇原创文章 · 获赞 11 · 访问量 4783
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章