最近用到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;
}