C++ Socket发送文件客户端代码

/*客户端代码头文件*/


#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


/**客户端源文件*/
#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;
	}

	CCSDef::TMSG_FILENAME* pRequestFilenameMsg = (CCSDef::TMSG_FILENAME*)pMsgHeader;
	printf("File Name: %s\n", pRequestFilenameMsg->szFileName);

	// 把文件的路径设置为C盘根目录下
	strcpy(g_szFileName, "c:\\");
	strcat(g_szFileName, pRequestFilenameMsg->szFileName);

	// 查找相同文件名的文件是否已经存在,如果存在报错退出
	FILE* pFile;
	if (NULL != (pFile = fopen(g_szFileName, "r")))
	{
		// 文件已经存在,要求重新输入一个文件
		printf("The file already exist!\n");
		CCSDef::TMSG_ERROR_MSG tMsgErrorMsg(MSG_FILEALREADYEXIT_ERROR);
		::send(g_sClient, (char*)(&tMsgErrorMsg), sizeof(CCSDef::TMSG_ERROR_MSG), 0);

		fclose(pFile);
		return false;
	}

	// 分配缓冲区开始接收文件,如果分配成功就给server端发送开始传送文件的要求
	g_pBuff = new char[g_lLength + 1];
	if (NULL != g_pBuff)
	{
		memset(g_pBuff, '\0', g_lLength + 1);
		printf("Now ready to get the file %s!\n", pRequestFilenameMsg->szFileName);
		CCSDef::TMSG_CLIENT_READY tMsgClientReady;

		if (SOCKET_ERROR == ::send(g_sClient, (char*)(&tMsgClientReady), sizeof(CCSDef::TMSG_CLIENT_READY), 0))
		{
			printf("Send Error!\n");
			exit(-1);
		}
	}
	else
	{
		printf("Alloc memory for file error!\n");
		exit(-1);
	}

	return true;
}

// 写入文件
bool WriteToFile(CCSDef::TMSG_HEADER *pMsgHeader)
{
	assert(NULL != pMsgHeader);

	CCSDef::TMSG_FILE* pMsgFile = (CCSDef::TMSG_FILE*)pMsgHeader;

	int nStart = pMsgFile->tFile.nStart;
	int nSize = pMsgFile->tFile.nSize;
	memcpy(g_pBuff + nStart, pMsgFile->tFile.szBuff, nSize);
	if (0 == nStart)
	{
		printf("Saving file into buffer...\n");
	}

	memcpy(g_pBuff + nStart, pMsgFile->tFile.szBuff, nSize);
	//printf("start = %d, size = %d\n", nStart, nSize);

	// 如果已经保存到缓冲区完毕就写入文件
	if (nStart + nSize >= g_lLength)
	{
		printf("Writing to disk....\n");
		// 写入文件
		FILE* pFile;
		pFile = fopen(g_szFileName, "w+b");
		fwrite(g_pBuff, sizeof(char), g_lLength, pFile);

		delete [] g_pBuff;
		g_pBuff = NULL;
		fclose(pFile);

		// 保存文件成功传送消息给server退出server
		CCSDef::TMSG_SENDFILESUCCESS tMsgSendFileSuccess;
		while (SOCKET_ERROR == ::send(g_sClient, (char*)(&tMsgSendFileSuccess), sizeof(CCSDef::TMSG_SENDFILESUCCESS), 0))
		{
		}

		printf("Save the file %s success!\n", g_szFileName);

		return true;
	}
	else
	{
		return false;
	}
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值