用c++ socket怎么实现发送文件夹

 我来答
tn瓶邪
2015-08-14 · TA获得超过1881个赞
知道小有建树答主
回答量:610
采纳率:98%
帮助的人:112万
展开全部
代码很长,如下:
/*server.h*/
#pragma comment(lib, "WS2_32")
#include <WinSock2.h>
#include <iostream>
//#include <stdio.h>
#include <assert.h>
#ifndef COMMONDEF_H
#define COMMONDEF_H
#define MAX_PACKET_SIZE 10240 // 数据包的最大长度,单位是sizeof(char)
#define MAXFILEDIRLENGTH 256 // 存放文件路径的最大长度
#define PORT 4096 // 端口号
#define SERVER_IP "127.0.0.1" // server端的IP地址
// 各种消息的宏定义
#define INVALID_MSG -1 // 无效的消息标识
#define MSG_FILENAME 1 // 文件的名称
#define MSG_FILELENGTH 2 // 传送文件的长度
#define MSG_CLIENT_READY 3 // 客户端准备接收文件
#define MSG_FILE 4 // 传送文件
#define MSG_SENDFILESUCCESS 5 // 传送文件成功
#define MSG_OPENFILE_ERROR 10 // 打开文件失败,可能是文件路径错误找不到文件等原因
#define MSG_FILEALREADYEXIT_ERROR 11 // 要保存的文件已经存在了
class CCSDef
{
public:
#pragma pack(1) // 使结构体的数据按照1字节来对齐,省空间
// 消息头
struct TMSG_HEADER
{
char cMsgID; // 消息标识
TMSG_HEADER(char MsgID = INVALID_MSG)
: cMsgID(MsgID)
{
}
};
// 请求传送的文件名
// 客户端传给服务器端的是全路径名称
// 服务器传回给客户端的是文件名
struct TMSG_FILENAME : public TMSG_HEADER
{
char szFileName[256]; // 保存文件名的字符数组
TMSG_FILENAME()
: TMSG_HEADER(MSG_FILENAME)
{
}
};
// 传送文件长度
struct TMSG_FILELENGTH : public TMSG_HEADER
{
long lLength;
TMSG_FILELENGTH(long length)
: TMSG_HEADER(MSG_FILELENGTH), lLength(length)
{
}
};
// Client端已经准备好了,要求Server端开始传送文件
struct TMSG_CLIENT_READY : public TMSG_HEADER
{
TMSG_CLIENT_READY()
: TMSG_HEADER(MSG_CLIENT_READY)
{
}
};
// 传送文件
struct TMSG_FILE : public TMSG_HEADER
{
union // 采用union保证了数据包的大小不大于MAX_PACKET_SIZE * sizeof(char)
{
char szBuff[MAX_PACKET_SIZE];
struct
{
int nStart;
int nSize;
char szBuff[MAX_PACKET_SIZE - 2 * sizeof(int)];
}tFile;
};
TMSG_FILE()
: TMSG_HEADER(MSG_FILE)
{
}
};
// 传送文件成功
struct TMSG_SENDFILESUCCESS : public TMSG_HEADER
{
TMSG_SENDFILESUCCESS()
: TMSG_HEADER(MSG_SENDFILESUCCESS)
{
}
};
// 传送出错信息,包括:
// MSG_OPENFILE_ERROR:打开文件失败
// MSG_FILEALREADYEXIT_ERROR:要保存的文件已经存在了
struct TMSG_ERROR_MSG : public TMSG_HEADER
{
TMSG_ERROR_MSG(char cErrorMsg)
: TMSG_HEADER(cErrorMsg)
{
}
};
#pragma pack()
};
#endif
/*server.cpp*/
#include "server.h"
char g_szNewFileName[MAXFILEDIRLENGTH];
char g_szBuff[MAX_PACKET_SIZE + 1];
long g_lLength;
char* g_pBuff = NULL;
// 初始化socket库
bool InitSocket();
// 关闭socket库
bool CloseSocket();
// 解析消息进行相应的处理
bool ProcessMsg(SOCKET sClient);
// 监听Client的消息
void ListenToClient();
// 打开文件
bool OpenFile(CCSDef::TMSG_HEADER* pMsgHeader, SOCKET sClient);
// 传送文件
bool SendFile(SOCKET sClient);
// 读取文件进入缓冲区
bool ReadFile(SOCKET sClient);
int main()
{
InitSocket();
ListenToClient();
CloseSocket();
return 0;
}
void ListenToClient()
{
// 创建socket套接字
SOCKET sListen = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == sListen)
{
printf("Init Socket Error!\n");
return;
}
// 绑定socket到一个本地地址
sockaddr_in sin;
sin.sin_family = AF_INET;
sin.sin_port = htons(PORT);
sin.sin_addr.S_un.S_addr = INADDR_ANY;
if (::bind(sListen, (LPSOCKADDR)&sin, sizeof(sockaddr_in)) == SOCKET_ERROR)
{
printf("Bind Error!\n");
return;
}
// 设置socket进入监听状态
if (::listen(sListen, 10) == SOCKET_ERROR)
{
printf("Listen Error!\n");
return;
}
printf("Listening To Client...\n");
// 循环接收client端的连接请求
sockaddr_in ClientAddr;
int nAddrLen = sizeof(sockaddr_in);
SOCKET sClient;
while (INVALID_SOCKET == (sClient = ::accept(sListen, (sockaddr*)&ClientAddr, &nAddrLen)))
{
}
while (true == ProcessMsg(sClient))
{
}
// 关闭同客户端的连接
::closesocket(sClient);
::closesocket(sListen);
}
bool InitSocket()
{
// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 2);
if (::WSAStartup(socketVersion, &wsaData) != 0)
{
printf("Init socket dll error\n");
return false;
}
return true;
}
bool CloseSocket()
{
// 释放winsock库
::WSACleanup();
if (NULL != g_pBuff)
{
delete [] g_pBuff;
g_pBuff = NULL;
}
return true;
}
bool ProcessMsg(SOCKET sClient)
{
int nRecv = ::recv(sClient, g_szBuff, MAX_PACKET_SIZE + 1, 0);
if (nRecv > 0)
{
g_szBuff[nRecv] = '\0';
}
// 解析命令
CCSDef::TMSG_HEADER* pMsgHeader = (CCSDef::TMSG_HEADER*)g_szBuff;
switch (pMsgHeader->cMsgID)
{
case MSG_FILENAME: // 文件名
{
OpenFile(pMsgHeader, sClient);
}
break;
case MSG_CLIENT_READY: // 客户端准备好了,开始传送文件
{
SendFile(sClient);
}
break;
case MSG_SENDFILESUCCESS: // 传送文件成功
{
printf("Send File Success!\n");
return false;
}
break;
case MSG_FILEALREADYEXIT_ERROR: // 要保存的文件已经存在了
{
printf("The file reay to send already exit!\n");
return false;
}
break;
}
return true;
}
bool ReadFile(SOCKET sClient)
{
if (NULL != g_pBuff)
{
return true;
}
// 打开文件
FILE *pFile;
if (NULL == (pFile = fopen(g_szNewFileName, "rb"))) // 打开文件失败
{
printf("Cannot find the file, request the client input file name again\n");
CCSDef::TMSG_ERROR_MSG tMsgErrorMsg(MSG_OPENFILE_ERROR);
::send(sClient, (char*)(&tMsgErrorMsg), sizeof(CCSDef::TMSG_ERROR_MSG), 0);
return false;
}
// 把文件的长度传回到client去
fseek(pFile, 0, SEEK_END);
g_lLength = ftell(pFile);
printf("File Length = %d\n", g_lLength);
CCSDef::TMSG_FILELENGTH tMsgFileLength(g_lLength);
::send(sClient, (char*)(&tMsgFileLength), sizeof(CCSDef::TMSG_FILELENGTH), 0);
// 处理文件全路径名,把文件名分解出来
char szDrive[_MAX_DRIVE], szDir[_MAX_DIR], szFname[_MAX_FNAME], szExt[_MAX_EXT];
_splitpath(g_szNewFileName, szDrive, szDir, szFname, szExt);
strcat(szFname,szExt);
CCSDef::TMSG_FILENAME tMsgFileName;
strcpy(tMsgFileName.szFileName, szFname);
printf("Send File Name: %s\n", tMsgFileName.szFileName);
::send(sClient, (char*)(&tMsgFileName), sizeof(CCSDef::TMSG_FILENAME), 0);
// 分配缓冲区读取文件内容
g_pBuff = new char[g_lLength + 1];
if (NULL == g_pBuff)
{
return false;
}
fseek(pFile, 0, SEEK_SET);
fread(g_pBuff, sizeof(char), g_lLength, pFile);
g_pBuff[g_lLength] = '\0';
fclose(pFile);
return true;
}
// 打开文件
bool OpenFile(CCSDef::TMSG_HEADER* pMsgHeader, SOCKET sClient)
{
CCSDef::TMSG_FILENAME* pRequestFilenameMsg = (CCSDef::TMSG_FILENAME*)pMsgHeader;
// 对文件路径名进行一些处理
char *p1, *p2;
for (p1 = pRequestFilenameMsg->szFileName, p2 = g_szNewFileName;
'\0' != *p1;
++p1, ++p2)
{
if ('\n' != *p1)
{
*p2 = *p1;
}
if ('\\' == *p2)
{
*(++p2) = '\\';
}
}
*p2 = '\0';
ReadFile(sClient);
return true;
}
// 传送文件
bool SendFile(SOCKET sClient)
{
if (NULL == g_pBuff)
{
ReadFile(sClient);
}
int nPacketBufferSize = MAX_PACKET_SIZE - 2 * sizeof(int); // 每个数据包存放文件的buffer大小
// 如果文件的长度大于每个数据包所能传送的buffer长度那么就分块传送
for (int i = 0; i < g_lLength; i += nPacketBufferSize)
{
CCSDef::TMSG_FILE tMsgFile;
tMsgFile.tFile.nStart = i;
if (i + nPacketBufferSize + 1> g_lLength)
{
tMsgFile.tFile.nSize = g_lLength - i;
}
else
{
tMsgFile.tFile.nSize = nPacketBufferSize;
}
//printf("start = %d, size = %d\n", tMsgFile.tFile.nStart, tMsgFile.tFile.nSize);
memcpy(tMsgFile.tFile.szBuff, g_pBuff + tMsgFile.tFile.nStart, tMsgFile.tFile.nSize);
::send(sClient, (char*)(&tMsgFile), sizeof(CCSDef::TMSG_FILE), 0);
Sleep(0.5);
}
delete [] g_pBuff;
g_pBuff = NULL;
return true;
}

/*client.h同server.h*/
/*client.cpp*/
#include "client.h"
long g_lLength = 0;
char* g_pBuff = NULL;
char g_szFileName[MAXFILEDIRLENGTH];
char g_szBuff[MAX_PACKET_SIZE + 1];
SOCKET g_sClient;
// 初始化socket库
bool InitSocket();
// 关闭socket库
bool CloseSocket();
// 把用户输入的文件路径传送到server端
bool SendFileNameToServer();
// 与server端连接
bool ConectToServer();
// 打开文件失败
bool OpenFileError(CCSDef::TMSG_HEADER *pMsgHeader);
// 分配空间以便写入文件
bool AllocateMemoryForFile(CCSDef::TMSG_HEADER *pMsgHeader);
// 写入文件
bool WriteToFile(CCSDef::TMSG_HEADER *pMsgHeader);
// 处理server端传送过来的消息
bool ProcessMsg();
int main()
{
InitSocket();
ConectToServer();
CloseSocket();
return 0;
}
// 初始化socket库
bool InitSocket()
{
// 初始化socket dll
WSADATA wsaData;
WORD socketVersion = MAKEWORD(2, 2);
if (::WSAStartup(socketVersion, &wsaData) != 0)
{
printf("Init socket dll error\n");
exit(-1);
}
return true;
}
// 关闭socket库
bool CloseSocket()
{
// 关闭套接字
::closesocket(g_sClient);
// 释放winsock库
::WSACleanup();
return true;
}
// 与server端连接进行文件的传输
bool ConectToServer()
{
// 初始化socket套接字
if (SOCKET_ERROR == (g_sClient = ::socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)))
{
printf("Init Socket Error!\n");
exit(-1);
}
sockaddr_in servAddr;
servAddr.sin_family = AF_INET;
servAddr.sin_port = htons(PORT);
servAddr.sin_addr.S_un.S_addr = ::inet_addr(SERVER_IP);
if (INVALID_SOCKET == (::connect(g_sClient, (sockaddr*)&servAddr, sizeof(sockaddr_in))))
{
printf("Connect to Server Error!\n");
exit(-1);
}
// 输入文件路径传输到server端
SendFileNameToServer();
// 接收server端传过来的信息,直到保存文件成功为止
while (true == ProcessMsg())
{
}
return true;
}
// 把用户输入的文件路径传送到server端
bool SendFileNameToServer()
{
char szFileName[MAXFILEDIRLENGTH];
printf("Input the File Directory: ");
fgets(szFileName, MAXFILEDIRLENGTH, stdin);
// 把文件路径发到server端
CCSDef::TMSG_FILENAME tMsgRequestFileName;
strcpy(tMsgRequestFileName.szFileName, szFileName);
if (SOCKET_ERROR == ::send(g_sClient, (char*)(&tMsgRequestFileName), sizeof(CCSDef::TMSG_FILENAME), 0))
{
printf("Send File Name Error!\n");
exit(-1);
}
return true;
}
// 处理server端传送过来的消息
bool ProcessMsg()
{
CCSDef::TMSG_HEADER *pMsgHeader;
int nRecv = ::recv(g_sClient, g_szBuff, MAX_PACKET_SIZE + 1, 0);

pMsgHeader = (CCSDef::TMSG_HEADER*)g_szBuff;
switch (pMsgHeader->cMsgID)
{
case MSG_OPENFILE_ERROR: // 打开文件错误
{
OpenFileError(pMsgHeader);
}
break;
case MSG_FILELENGTH: // 文件的长度
{
if (0 == g_lLength)
{
g_lLength = ((CCSDef::TMSG_FILELENGTH*)pMsgHeader)->lLength;
printf("File Length: %d\n", g_lLength);
}
}
break;
case MSG_FILENAME: // 文件名
{
return AllocateMemoryForFile(pMsgHeader);
}
break;
case MSG_FILE: // 传送文件,写入文件成功之后退出这个函数
{
if (WriteToFile(pMsgHeader))
{
return false;
}
}
break;
}
return true;
}
// 打开文件失败
bool OpenFileError(CCSDef::TMSG_HEADER *pMsgHeader)
{
if (NULL != g_pBuff)
return true;
assert(NULL != pMsgHeader);
printf("Cannot find file!Please input again!\n");
// 重新输入文件名称
SendFileNameToServer();
return true;
}
// 查找是否已经存在了要保存的文件,同时分配缓冲区保存文件
bool AllocateMemoryForFile(CCSDef::TMSG_HEADER *pMsgHeader)
{
assert(NULL != pMsgHeader);
if (NULL != g_pBuff)
{
return true;
}
百度网友6eab688
2012-07-24 · TA获得超过4690个赞
知道大有可为答主
回答量:962
采纳率:50%
帮助的人:941万
展开全部
基础:
1. 会发送一个文件
2. 会遍历一个文件夹下的所有文件

然后用下面两种方法之一:
1. 将文件夹压缩成一个文件,可以使用zlib库,发送过去后解压缩
2. 遍历所有文件,在每个发送的文件前面带上 相对路径,到远方后按相对路径存放
本回答被网友采纳
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
馒头上线了
2015-08-13 · TA获得超过221个赞
知道小有建树答主
回答量:162
采纳率:66%
帮助的人:88万
展开全部
主要函数或步骤:

WSAStartup, 初始化,WSACleanup,结束
socket(, ,) 构造函数,要有socket的instance才能实现传输
send()
recv()
listen(), server端开始要监听自己的端口号有没有被连接
bind(),server的用来listen()的socket绑定address
accept(),如果没有client要连接,server在调用时就阻塞,有client要连接,就从这个要连接的队列里取出然后accept,然后server产生一个新的socket,而之前在listen()的socket是和这个不一样的,微软为何要弄两个socket出来呢,网上有一些解释,似乎是为了使用时更清楚一点
可以看看这个
http://blog.csdn.net/jackyguo1992/article/details/18020225
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
匿名用户
2012-07-24
展开全部
对,就是推荐答案里的方法
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
收起 1条折叠回答
收起 更多回答(2)
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式