windows网络编程实验4采用C++进行TCP通信之多线程文件传输

实验要求:使服务器与多个客户端进行通信,同时接收多个客户端上传的文件。

服务端代码:

#include"iostream"
#include"afxmt.h"
#include"process.h"
#include"winsock2.h"
#include"fstream"
#include"WS2tcpip.h"
#include"direct.h"


#define PORT 65432
#pragma comment(lib,"ws2_32.lib")

using namespace std;
struct fileMessage
{
	char fileName[256];
	long int fileSize;
};


/*主程序和线程函数共用的全局变量定义*/
char fname[128] = { 0 };			//发送给客户端的无路径信息的文件名
ifstream inFile;					//定义文件的输入流
CMutex Section;						//创建互斥对象
void rdFile(void* par);			//发送文件的线程函数声明

/*主函数*/

int main()
{
	SOCKET sock_server;						//定义监听套接字
	struct sockaddr_in addr;
	struct sockaddr_in client_addr;	//存放本地地址和客户地址的变量
	SOCKET newsock;							//储存accept()返回的套接字描述符
	/*初始化winsock DLL*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "加载winSock动态链接库失败!\n";
		return 0;
	}

	/*创建监听套接字*/
	if ((sock_server = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		cout << "创建套接字失败!\n";
		WSACleanup();
		return 0;
	}

	/*绑定IP地址与端口*/
	memset((void*)&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(65432);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(sock_server, (struct sockaddr*)&addr, sizeof(addr)) != 0)
	{
		cout << "绑定失败!\n";
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	if (listen(sock_server, 5) != 0)
	{
		cout << "listen函数调用失败!\n";
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	else
	{
		cout << "listenning.....\n";
	}

	/*接收客户连接请求*/
	int addr_len = sizeof(struct sockaddr_in);
	while (true)
	{
		newsock = accept(sock_server, (LPSOCKADDR)&client_addr, &addr_len);
		if (newsock != INVALID_SOCKET)
		{
			cout << "一个客户连接成功!" << endl;
			_beginthread(rdFile, 0, (LPVOID)newsock);

		}
		else
		{
			break;
		}

	}

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

}

void rdFile(void* par)
{
	/*定义文件传输所需变量*/
	struct fileMessage fileMsg;
	SOCKET sock = (SOCKET)par;
	long int filelen;
	char filename[500] = "C:\\Users\\86152\\source\\repos\\textfile"; //指定文件的保存目录
	char ok[3] = "OK";
	char fileBuffer[1000];		//接收文件数据的缓冲区
	_mkdir(filename);		//_mkdir()用于创建文件夹,其声明包含在direct.h中

	/*接收文件名及文件长度信息*/
	if ((filelen = recv(sock, (char*)&fileMsg, sizeof(fileMsg), 0)) <= 0)
	{
		cout << "未接收到文件名及文件长度!\n";
		closesocket(sock);
		WSACleanup();
		return;
	}

	filelen = ntohl(fileMsg.fileSize);
	strcat_s(filename, fileMsg.fileName);
	ofstream outFile(filename, ios::out | ios::binary);		//创建文件对象
	if (!outFile.is_open())
	{
		cout << "Cannot open" << filename << endl;
		closesocket(sock);
		WSACleanup();
		return;										//文件打开失败则退出
	}
	send(sock, ok, sizeof(ok), 0);				//发送接收文件数据的确认信息
	int size = 0;
	do
	{
		size = recv(sock, fileBuffer, sizeof(fileBuffer), 0);
		if (size <= 0)break;
		outFile.write(fileBuffer, size);
		filelen -= size;
	} while (filelen > 0);

	if (filelen == 0)
	{
		cout << "Transfer finished!\n";
	}
	else
	{
		cout << "Transfer Failed!\n";
	}
	outFile.close();
	closesocket(sock);

}

客户端代码:

#include<iostream>
#include"fstream"
#include"winsock2.h"
#include"WS2tcpip.h"
#include"direct.h"
#pragma comment(lib,"ws2_32.lib")

using namespace std;
struct fileMessage			//定义存储文件信息的结构体
{
	char fileName[256];
	long int fileSize;

};

int main()
{
	/*定义网络连接的相关变量*/
	int sock_client;					//定义套接字
	struct sockaddr_in server_addr;			//用于存放服务器地址的变量
	int addr_len = sizeof(struct sockaddr_in);		//地址长度
	/*初始化winsock DLL*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
	{
		cout << "加载winsock动态链接库失败!\n";
		return 0;
	}

	char filename[500];						//用于存储要传输的文件的文件路径
	cout << "输入要输入的文件路径:";
	cin.getline(filename, 500);

	/*创建套接字*/
	if ((sock_client = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		cout << "创建套接字失败!\n";
		WSACleanup();
		return 0;
	}

	/*输入服务器IP地址及端口号*/
	char IP[20];
	//	unsigned short port;
	in_addr a;
	cout << "请输入服务器IP地址:";
	cin >> IP;
	inet_pton(AF_INET, IP, &a);
	memset((void*)&server_addr, 0, addr_len);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(65432);
	server_addr.sin_addr.s_addr = a.S_un.S_addr;
	if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0)
	{
		cout << "连接失败!\n";
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}



	char OK[3], fileBuffer[1000];						//定义接收“OK”的缓冲区和发送缓冲区
	struct fileMessage fileMsg;							//定义保存文件名及文件长度的结构变量
	ifstream inFile(filename, ios::in | ios::binary);	//定义文件对象并打开文件
	if (!inFile.is_open())
	{
		cout << "CAnnot open" << filename << endl;
		closesocket(sock_client);
		WSACleanup();
		return 0;										//文件打开失败则退出
	}

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

	/*获取文件长度并存入结构变量fileMsg中*/
	inFile.seekg(0, ios::end);							//将文件的位置指针移到文件末尾
	size = inFile.tellg();								//获取当前文件位置指针值
	fileMsg.fileSize = htonl(size);						//将文件长度存入结构变量fileMeg
	send(sock_client, (char*)&fileMsg, sizeof(fileMsg), 0);//发送fileMeg
	if (recv(sock_client, OK, sizeof(OK), 0) <= 0)				//接收对方发来的OK信息
	{
		cout << "接收OK失败,程序退出!\n";
		closesocket(sock_client);
		WSACleanup();
		return 0;

	}
	if (strcmp(OK, "OK") == 0)							//如果对方已准备好接收则发送文件内容
	{
		inFile.seekg(0, ios::beg);					//将文件的位置指针返回到文件头
		while (!inFile.eof())
		{
			inFile.read(fileBuffer, sizeof(fileBuffer));
			size = inFile.gcount();					//读取实际读取的字节数
			send(sock_client, fileBuffer, size, 0);

		}
		cout << "File Transfer Finished!\n";
		inFile.close();								//关闭文件
	}
	else
	{
		cout << "对方无法接收文件!";
	}
	closesocket(sock_client);
	WSACleanup();
	return 0;


}

实现效果:

 

实验要求:服务器同时向多个客户端发送文件

#include<iostream>
#include"fstream"
#include"winsock2.h"
#pragma comment(lib,"ws2_32.lib")

using namespace std;
struct fileMessage			//定义存储文件信息的结构体
{
	char fileName[256];
	long int fileSize;

};

int main()
{
	SOCKET sock_server;						//定义监听套接字
	struct sockaddr_in addr;
	struct sockaddr_in client_addr;	//存放本地地址和客户地址的变量
	SOCKET newsock;							//储存accept()返回的套接字描述符
	/*初始化winsock DLL*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
	{
		cout << "加载winSock动态链接库失败!\n";
		return 0;
	}

	char filename[500];						//用于存储要传输的文件的文件路径
	cout << "输入要输入的文件路径:";
	cin.getline(filename, 500);


	/*创建监听套接字*/
	if ((sock_server=socket(AF_INET,SOCK_STREAM,0))<0)
	{
		cout << "创建套接字失败!\n";
		WSACleanup();
		return 0;
	}

	/*绑定IP地址与端口*/
	memset((void*)&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(65432);
	addr.sin_addr.s_addr = htonl(INADDR_ANY);
	if (bind(sock_server,(struct sockaddr*)&addr,sizeof(addr))!=0)
	{
		cout << "绑定失败!\n";
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	if (listen(sock_server,5)!=0)
	{
		cout << "listen函数调用失败!\n";
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	else
	{
		cout << "listenning.....\n";
	}

	/*接收客户连接请求*/
	int addr_len = sizeof(struct sockaddr_in);
	if ((newsock=accept(sock_server,(struct sockaddr*)&client_addr,&addr_len))==INVALID_SOCKET)
	{
		cout << "accept函数调用失败!\n";
		closesocket(sock_server);
		WSACleanup();
		return 0;
	}
	cout << "客户连接成功!" << endl;
	char OK[3], fileBuffer[1000];						//定义接收“OK”的缓冲区和发送缓冲区
	struct fileMessage fileMsg;							//定义保存文件名及文件长度的结构变量
	ifstream inFile(filename, ios::in | ios::binary);	//定义文件对象并打开文件
	if (!inFile.is_open())
	{
		cout << "CAnnot open" << filename << endl;
		closesocket(newsock);
		closesocket(sock_server);
		WSACleanup();
		return 0;										//文件打开失败则退出
	}

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

	/*获取文件长度并存入结构变量fileMsg中*/
	inFile.seekg(0, ios::end);							//将文件的位置指针移到文件末尾
	size = inFile.tellg();								//获取当前文件位置指针值
	fileMsg.fileSize = htonl(size);						//将文件长度存入结构变量fileMeg
	send(newsock, (char*)&fileMsg, sizeof(fileMsg), 0);//发送fileMeg
	if (recv(newsock,OK,sizeof(OK),0)<=0)				//接收对方发来的OK信息
	{
		cout << "接收OK失败,程序退出!\n";
		closesocket(newsock);
		closesocket(sock_server);
		WSACleanup();
		return 0;

	}
	if (strcmp(OK,"OK")==0)							//如果对方已准备好接收则发送文件内容
	{
		inFile.seekg(0, ios::beg);					//将文件的位置指针返回到文件头
		while (!inFile.eof())
		{
			inFile.read(fileBuffer, sizeof(fileBuffer));
			size = inFile.gcount();					//读取实际读取的字节数
			send(newsock, fileBuffer, size, 0);

		}
		cout << "File Transfer Finished!\n";
		inFile.close();								//关闭文件
	}
	else
	{
		cout << "对方无法接收文件!";
	}
	closesocket(newsock);
	closesocket(sock_server);
	WSACleanup();
	return 0;
}

 客户端代码:

#include<iostream>
#include"fstream"
#include"winsock2.h"
#include"WS2tcpip.h"
#include"direct.h"
#pragma comment(lib,"ws2_32.lib")

using namespace std;
struct fileMessage
{
	char fileName[256];
	long int fileSize;
};

int main()
{
	/*定义网络连接的相关变量*/
	int sock_client;					//定义套接字
	struct sockaddr_in server_addr;			//用于存放服务器地址的变量
	int addr_len = sizeof(struct sockaddr_in);		//地址长度
	/*初始化winsock DLL*/
	WSADATA wsaData;
	if (WSAStartup(MAKEWORD(2,2),&wsaData)!=0)
	{
		cout << "加载winsock动态链接库失败!\n";
		return 0;
	}

	/*创建套接字*/
	if ((sock_client=socket(AF_INET,SOCK_STREAM,0))<0)
	{
		cout << "创建套接字失败!\n";
		WSACleanup();
		return 0;
	}

	/*输入服务器IP地址及端口号*/
	char IP[20];
//	unsigned short port;
	in_addr a;
	cout << "请输入服务器IP地址:";
	cin >> IP;
	inet_pton(AF_INET, IP, &a);
	memset((void*)&server_addr, 0, addr_len);
	server_addr.sin_family = AF_INET;
	server_addr.sin_port = htons(65432);
	server_addr.sin_addr.s_addr = a.S_un.S_addr;
	if (connect(sock_client, (struct sockaddr*)&server_addr, addr_len) != 0)
	{
		cout << "连接失败!\n";
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}

	/*定义文件传输所需变量*/
	struct fileMessage fileMsg;
	long int filelen;
	char filename[500] = "D:\\BaiduNetdiskDownload\\visualstudio\\vsfile\\transferfileclient"; //指定文件的保存目录
	char ok[3] = "OK";
	char fileBuffer[1000];		//接收文件数据的缓冲区
	_mkdir(filename);		//_mkdir()用于创建文件夹,其声明包含在direct.h中

	/*接收文件名及文件长度信息*/
	if ((filelen=recv(sock_client,(char*)&fileMsg,sizeof(fileMsg),0))<=0)
	{
		cout << "未接收到文件名及文件长度!\n";
		closesocket(sock_client);
		WSACleanup();
		return 0;
	}

	filelen = ntohl(fileMsg.fileSize);
	strcat_s(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;										//文件打开失败则退出
	}
	send(sock_client, ok, sizeof(ok), 0);				//发送接收文件数据的确认信息
	int size = 0;
	do
	{
		size = recv(sock_client, fileBuffer, sizeof(fileBuffer), 0);
		if (size <= 0)break;
		outFile.write(fileBuffer, size);
		filelen -= size;
	} while (filelen>0);

	if (filelen==0)
	{
		cout << "Transfer finished!\n";
	}
	else
	{
		cout << "Transfer Failed!\n";
	}
	outFile.close();
	closesocket(sock_client);
	WSACleanup();
	return 0;

}

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值