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

来源:互联网 发布:java的应用领域与方向 编辑:程序博客网 时间:2024/05/20 03:44
/*客户端代码头文件*/#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 dllWSADATA 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退出serverCCSDef::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;}}