跨平台文件传输工具

最近用到freebsd10.2,然而倒腾图形界面始终没有成功,各种代码无法拷贝到bsd上去,不可能用vi或者ee重复再敲一遍。

vmtools似乎也没法安装,于是就用ee敲了个最简单的bsd上的服务端,接收文件并保存到本地。精简版代码如下: 


#include <sys/socket.h>
#include <arpa/inet.h>
#include <string.h>
#include <fstream>
#include <string>

struct FileCopyInfo
{
	char fileName[128];
	char fileLength;
	unsigned reserved;
};

int main(int argc, char **argv)
{
	auto serv = socket(AF_INET, SOCK_STREAM, 0);
	sockaddr_in addr;
	memset(&addr, 0, sizeof(addr));
	addr.sin_family = AF_INET;
	addr.sin_port = htons(argv[1]);
	bind(serv, (sockaddr*)&addr, sizeof(sockaddr));
	listen(serv, 5);
	while (true)
	{
		sockaddr_in client_addr;
		socklen_t length = sizeof(client_addr);
		auto con = accept(serv, (struct sockaddr*)&client_addr, &length);
		FileCopyInfo cpyInfo;
		recv(con, (char*)&cpyInfo, sizeof(cpyInfo), 0);

		char buf[1024];
		std::ofstream ofs(argv[2], std::ios::binary | std::ios::out);
		int s = 0;
		do
		{
			s = recv(con, buf, 1024, 0);
			ofs.write(buf, s);
		} while (s>0);
	}
	return 0;
}


可以先在windows上编译出完整版作为一个客户端来连接bsd上的精简版,然后将完整版作为文件传输到bsd,再在bsd上编译出完整版,就可以实现双向文件拷贝了。

完整版可以在windows/linux/bsd上编译,linux上需要指定-std=c++11 windows上最好是vs2013及以后版本,完整版如下:

#ifdef WIN32
#include <WinSock2.h>
#include <WS2tcpip.h>
#pragma comment(lib, "ws2_32.lib")
#else
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
// g++ this.cpp -std=c++11 -lpthread -o test
#endif

#include <string.h>
#include <iostream>
#include <fstream>
#include <thread>
#include <string>
#include <sstream>
#include <algorithm>

struct SocketTool
{
	SocketTool()
	{
#ifdef WIN32
		WORD wVersionRequested;
		WSADATA wsaData;
		wVersionRequested = MAKEWORD(2, 2);
		WSAStartup(wVersionRequested, &wsaData);
#endif
	}

	template <typename SOCKET_TYPE>
	static int CloseSocket(SOCKET_TYPE skt)
	{
#ifdef WIN32
		return closesocket(skt);
#else
		return close(skt);
#endif
	}

	static sockaddr_in GenInAddr(const char *szIP, unsigned uPort)
	{
		sockaddr_in addr;
		memset(&addr, 0, sizeof(addr));
		addr.sin_family = AF_INET;
		addr.sin_port = htons(uPort);
#ifdef WIN32
		inet_pton(AF_INET, szIP, &addr.sin_addr);
#else
		inet_aton(szIP, &addr.sin_addr);
#endif
		return addr;
	}

	static std::string PrintInAddr(const sockaddr_in& addr)
	{
		char buf[128] = { 0 };
		inet_ntop(AF_INET, (void*)&addr.sin_addr, buf, sizeof(buf));
		auto port = ntohs(addr.sin_port);
		std::stringstream ss;
		ss << buf << ":" << port;
		return ss.str();
	}

	~SocketTool()
	{
#ifdef WIN32
		WSACleanup();
#endif
	}
};

struct FileCopyInfo
{
	char fileName[128];
	unsigned fileLength;
	unsigned reserved;
};

#ifdef WIN32
#include <WinSock2.h>
#else
#include <arpa/inet.h>
#endif

void N2L(FileCopyInfo& cpyInfo)
{
	cpyInfo.fileLength = ntohl(cpyInfo.fileLength);
}

void L2N(FileCopyInfo& cpyInfo)
{
	cpyInfo.fileLength = htonl(cpyInfo.fileLength);
}

template <typename SocketType>
bool SendData(SocketType s, const char* buf, unsigned bufLen)
{
	unsigned rest = bufLen;
	unsigned sended = 0;
	while (rest > 0)
	{
		auto r = send(s, buf + sended, rest, 0);
		if (r <= 0)
		{
			std::cout << "send failed" << std::endl;
			return false;
		}
		else
		{
			sended += r;
			rest -= r;
		}
	}
	return true;
}

bool SendFile(const char *pLocalFile, const char *ip, int port)
{
	std::ifstream ifs(pLocalFile, std::ios::in | std::ios::binary);
	if (!ifs.is_open())
	{
		std::cout << "open loacal file failed!" << std::endl;
		return false;
	}

	SocketTool sktInit;
	auto s = socket(AF_INET, SOCK_STREAM, 0);
	auto addr = SocketTool::GenInAddr(ip, port);
	auto ret = connect(s, (sockaddr*)&addr, sizeof(addr));
	if (ret != 0)
	{
		std::stringstream ss;
		ss << "connect " << ip << ":" << port << "failed" << std::endl;
		std::cout << ss.str() << std::endl;
	}

	FileCopyInfo cpyInfo;
	const char* pSrcName = strrchr(pLocalFile, '/');
	if (pSrcName == nullptr)
	{
		pSrcName = pLocalFile;
	}
	else
	{
		++pSrcName;
	}
	strcpy(cpyInfo.fileName, pSrcName);


	ifs.seekg(0, std::ios::end);
	auto fileLen = ifs.tellg();
	ifs.seekg(0, std::ios::beg);


	std::cout << "Sending " << fileLen << " bytes...";
	unsigned uSended = 0;
	cpyInfo.fileLength = fileLen;
	L2N(cpyInfo);
	if (SendData(s, (const char*)&cpyInfo, sizeof(cpyInfo)))
	{
		char buf[1024] = { 0 };
		do
		{
			ifs.read(buf, sizeof(buf));
			auto l = ifs.gcount();
			if (SendData(s, buf, l))
			{
				uSended += l; 
			}
			else
			{
				break;
			}
		} while (!ifs.eof());
	}
	std::cout << uSended << "/" << fileLen << " bytes sended!" << std::endl;
	SocketTool::CloseSocket(s);
	return uSended == fileLen;
}

template <typename SocketType>
bool RecvData(SocketType s, char* buf, unsigned bufLen)
{
	unsigned recved = 0;
	auto rest = bufLen;
	while (rest > 0)
	{
		auto r = recv(s, buf + recved, rest, 0);
		if (r <= 0)
		{
			std::cout << "recv failed" << std::endl;
			return false;
		}
		else
		{
			recved += r;
			rest -= r;
		}
	}
	return true;
}
bool RecvFile(const char *pLocalDir, int port)
{
	SocketTool sktTool;
	auto serv = socket(AF_INET, SOCK_STREAM, 0);
	int reuse = 1;
	if (setsockopt(serv, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) == -1)
	{
		std::cout << "setsockopt SO_REUSEADDR failed" << std::endl;
		return false;
	}
	auto addr = SocketTool::GenInAddr("0.0.0.0", port);
	if (bind(serv, (sockaddr*)&addr, sizeof(sockaddr)) == -1)
	{
		std::cout << "bind failed" << std::endl;
		return false;
	}
	if (listen(serv, 5) == -1)
	{
		std::cout << "listen failed" << std::endl;
		return false;
	}

	while (true)
	{
		sockaddr_in client_addr;
		socklen_t length = sizeof(client_addr);
		auto con = accept(serv, (struct sockaddr*)&client_addr, &length);
		if (con < 0)
		{
			std::cout << "accept failed!\n" << std::endl;
		}
		else
		{
			auto strClient = SocketTool::PrintInAddr(client_addr);
			std::string strLocalDir(pLocalDir);
			if (strLocalDir.back() != '/')
			{
				strLocalDir += "/";
			}
			FileCopyInfo cpyInfo;
			if (RecvData(con, (char*)&cpyInfo, sizeof(cpyInfo)))
			{
				N2L(cpyInfo);
				std::cout << "Reading " << cpyInfo.fileName << " (" << cpyInfo.fileLength << "bytes) from " << strClient << "..." << std::endl;
				std::ofstream ofs(strLocalDir + cpyInfo.fileName, std::ios::out | std::ios::binary);
				if (ofs.is_open())
				{
					char buf[1024] = { 0 };
					unsigned uRest = cpyInfo.fileLength;
					while (uRest > 0)
					{
						auto uRead = uRest;
						if (uRead > sizeof(buf))
						{
							uRead = sizeof(buf);
						}
						if (RecvData(con, buf, uRead))
						{
							ofs.write(buf, uRead);
							uRest -= uRead;
						}
						else
						{
							break;
						}
					}
					std::cout << "recv finished: " << cpyInfo.fileLength - uRest << "/" << cpyInfo.fileLength << std::endl;
				}
				else
				{
					std::cout << "create file failed!" << std::endl;					
				}
			}
		}
		SocketTool::CloseSocket(con);
	}
	SocketTool::CloseSocket(serv);
}



int main(int argc, char **argv)
{
	if (argc == 4)
	{
		char *ip = argv[1];
		int port = atoi(argv[2]);
		char *localFile = argv[3];

		SendFile(localFile, ip, port);
	}
	else if (argc == 3)
	{
		int port = atoi(argv[1]);
		char *localDir = argv[2];
		RecvFile(localDir, port);
	}
	else
	{
		std::cout << "usage: \n\tFileCpy remoteip remoteport localfile\n\tFileCpy localport localdir" << std::endl;
		return 0;
	}

	return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值