windows环境下C++多线程文件传输

把上午写的传输字符串代码改了一下,本来是想实现客户端和服务器一对一多线程分块传输的,结果发现好像变成了一个服务器对多个客户端,每个客户端分配一条线程来处理文件传输任务的模式...

直接上代码,使用的是简单的fstream操作。
Sever代码:

#include "stdafx.h"
#include  //windows socket的头文件
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件

using namespace std;

mutex m;

//定义结构体用来设置
typedef struct my_file
{
	SOCKET clientSocket; //文件内部包含了一个SOCKET 用于和客户端进行通信
	sockaddr_in clientAddr; //用于保存客户端的socket地址
	int id; //文件块的序号
}F;

DWORD WINAPI transmmit(const LPVOID arg)
{
	//实际上这里也可以不加锁,上锁是为了方便看输出
	m.lock();

	F *temp = (F*)arg;
	//获取文件的序号
	//int file_id = temp->id;
	//获取客户机的端口号
	//ntohs(temp -> clientAddr.sin_port); 
	cout << "测试开始,等待客户端发送消息..." << endl;
	//从客户端处接受数据
	/*
	char Buffer[MAXBYTE] = { 0 }; //缓冲区
	recv(temp->clientSocket, Buffer, MAXBYTE, 0); //recv方法 从客户端通过clientScocket接收
	cout << "线程" << temp->id << "从客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口收到:" << Buffer << endl;
	*/
	char file_name[100] = { 0 }; //文件路径
	cout << "输入传输文件路径: ";
	cin >> file_name;
	FILE *fp = fopen(file_name, "rb"); //将文件按二进制读取
	if (fp == NULL)
	{
		cout << "文件" << file_name << "出错或不存在" << endl;
	}
	else
	{
		char Buffer[MAXBYTE] = { 0 }; //文件缓冲区
		int size = 0; //读取的文件长度
		//每次读取完之后清空缓存区,以便下一块文件读入
		while ((size = fread(Buffer, sizeof(char), MAXBYTE, fp)) > 0) 
		{
			//返回非0值表示send错误
			if (send(temp->clientSocket, Buffer, size, NULL) < 0)
			{
				cout << "传输出错,请检查网络配置。" << endl;
			}
			memset(&Buffer, 0, MAXBYTE);
		}
		cout << temp->id << "线程已成功发送" << file_name << endl;
		fclose(fp);
	}


	/*
	//发送简单的字符串到客户端
	const char* s = "Server file";
	send(temp->clientSocket, s, strlen(s)*sizeof(char)+1, NULL);
	cout << "线程" << temp->id << "通过客户端的" << ntohs(temp->clientAddr.sin_port) << "号端口发送:" << s << endl;
	*/

	m.unlock();

	return 0;
}



int main()
{
	WSADATA wsaData;
	//第一个参数是winsocket load的版本号(2.2)
	WSAStartup(MAKEWORD(2, 3), &wsaData);
	//创建服务器端的socket(协议族, sokcet类型)
	SOCKET servSocket = socket(AF_INET, SOCK_STREAM, 0);//如果改成SOCK_DGRAM则使用UDP
	sockaddr_in servAddr; //服务器的socket地址,包含sin_addr表示IP地址,sin_port保持端口号和sin_zero填充字节
	memset(&servAddr, 0, sizeof(SOCKADDR)); //初始化socket地址
	servAddr.sin_family = PF_INET; //设置使用的协议族
	servAddr.sin_port = htons(2017); //设置使用的端口
	servAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); //define s_addr = S_un.S_addr
	::bind(servSocket, (SOCKADDR *)&servAddr, sizeof(SOCKADDR)); //将之前创建的servSocket和端口,IP地址绑定

	HANDLE hThread[2]; //获取句柄
	listen(servSocket, 1); //监听服务器端口
	for (int i = 0; i < 1; i++)
	{
		F *temp = new F; //创建新的传输结构体
		sockaddr_in clntAddr;
		int nSize = sizeof(SOCKADDR);
		SOCKET clientSock = accept(servSocket, (SOCKADDR*)&clntAddr, &nSize);
		//temp数据成员赋值
		temp->clientSocket = clientSock;
		temp->id = i + 1;
		temp->clientAddr = clntAddr;
		//通过句柄创建子线程
		hThread[i] = CreateThread(NULL, 0, &transmmit, temp, 0, NULL);
	}
	//等待子线程完成
	WaitForMultipleObjects(1, hThread, TRUE, INFINITE);
	cout << "错误代码: " << WSAGetLastError() << endl;

	//关闭socket,释放winsock
	closesocket(servSocket);
	WSACleanup();

	cout << "服务器连接已关闭。" << endl;
	system("pause");

	return 0;
}


Client端代码:

#include "stdafx.h"
#include  //windows socket的头文件
#include 
#include 
#include 
#include 

#pragma comment(lib, "ws2_32.lib") //连接winsock2.h的静态库文件

using namespace std;

int main()
{
	//加载winsock库
	WSADATA wsadata;
	WSAStartup(MAKEWORD(2, 3), &wsadata);

	//客户端socket
	SOCKET clientSock = socket(PF_INET, SOCK_STREAM, 0);
	//初始化socket信息
	sockaddr_in clientAddr;
	memset(&clientAddr, 0, sizeof(SOCKADDR));
	//clientAddr.sin_addr.s_addr = htonl(INADDR_ANY);
	clientAddr.sin_addr.s_addr = inet_addr("127.0.0.1");
	clientAddr.sin_family = PF_INET;
	clientAddr.sin_port = htons(2017);
	//建立连接
	connect(clientSock, (SOCKADDR*)&clientAddr, sizeof(SOCKADDR));

	cout << "已建立连接。" << endl;

	/*
	char* s = new char[100];
	cout << "请输入你要发送的文字消息: ";
	cin >> s;
	send(clientSock, s, strlen(s)*sizeof(char) + 1, NULL);
	cout << "已发送:" << s << endl;
	*/

	char Buffer[MAXBYTE] = { 0 }; // 文件缓冲区
	char wb_file[100] = { 0 }; //写入的文件

	cout << "请输入想要写入的文件: ";
	cin >> wb_file;

	FILE *fp = fopen(wb_file, "wb");
	if (fp == NULL)
	{
		cout << "操作文件时出错" << endl;
		system("pause");
	}
	else
	{
		memset(&Buffer, 0, MAXBYTE);
		int size = 0;
		//当成功接收文件(size > 0)时,判断写入的时候文件长度是否等于接收的长度
		while ((size = recv(clientSock, Buffer, MAXBYTE, 0)) > 0)
		{
			if (fwrite(Buffer, sizeof(char), size, fp) < size)
			{
				cout << "写入出错,部分文件缺失。" << endl;
			}
			//清空缓存区以便下一次接收
			memset(&Buffer, 0, MAXBYTE);
		}
		cout << "接收完成" << endl;
		fclose(fp);
	}
	
	closesocket(clientSock);
	WSACleanup();

	cout << "客户端连接已关闭。" << endl;
	system("pause");

	return 0;
}


因为之前用了WaitForMultipleObjects,所以客户端即使已经接收完成,亦不会输出接收完成的信息,只有关闭服务器的时候才会输出...

接下来思考一下怎么实现大文件分块传输的问题吧_(:з)∠)_


你可能感兴趣的:(C++)