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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章