使用TCP协议实现文件传输.doc

上传人:wux****ua 文档编号:8871247 上传时间:2020-04-01 格式:DOC 页数:17 大小:84.02KB
返回 下载 相关 举报
使用TCP协议实现文件传输.doc_第1页
第1页 / 共17页
使用TCP协议实现文件传输.doc_第2页
第2页 / 共17页
使用TCP协议实现文件传输.doc_第3页
第3页 / 共17页
点击查看更多>>
资源描述
使用TCP协议实现文件传输2013-01-18 10:35:43 我来说两句 作者:hanchaoqi收藏 我要投稿 使用TCP协议实现文件传输。程序会分为服务器端和客户端,首先运行服务器端,监听来自客户端的连接,客户端运行后会通过程序内的服务器端IP地址,向服 务器发送连接请求。双方建立请求之后,客户端将所需文件的文件名和绝对路径传输给服务器,如果服务器找到此文件,则将此文件传输给客户端,然后断开连接。 具体算法描述如下:【1】服务器端:1、初始化socket服务2、监听连接请求并做相应的处理2.1创建监听套接字2.2监听套接口2.3接受套接字的连接2.4接收客户端传来的数据case 文件绝对路径:按照路径找到文件,并打开。提取本地文件名,发回给客户端发送文件总长度给客户端case 已准备接收文件完毕if 发送缓冲区为空读取文件,写入缓冲区将文件流分成大小相同的组(最后一组可能会小一点),顺次发送给客户端将缓冲区清空case 文件成功传送打印消息,退出case 文件已存在打印消息,退出2.5关闭同客户端的连接3、释放socket服务【2】客户端:1、初始化socket,winsock服务2、连接服务器,进行数据的传输2.1初始化,创建套接字2.2通过IP地址,向服务器发送连接请求,建立连接2.3主动发送所求文件绝对路径2.4接受服务器端数据并做相应处理case 打开文件错误:重新发送文件绝对路径至服务器,请求重发case 文件长度:打印消息case 文件名:if 文件已经存在发送“文件已经存在”else分配缓冲区,并向服务器发送“Ready”消息case 文件流:为已接收文件名创建文件打开文件,将文件流数据写入文件,直至接收所有分组数据发送“成功接收“消息3、关闭套接字释放服务源程序:【1】服务器端:头文件:cpp /*server.h*/ #pragma comment(lib, WS2_32) #include #include #include #include #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 szFileName256; / 保存文件名的字符数组 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 szBuffMAX_PACKET_SIZE; struct int nStart; int nSize; char szBuffMAX_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 cpp文件:cpp /*Server.cpp*/ #includeServer.h char g_szNewFileNameMAXFILEDIRLENGTH; char g_szBuffMAX_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* pMagHeader,SOCKET sClient); /传送文件 bool SendFile(SOCKET sClient); /读取文件进缓冲区 bool ReadFile(SOCKET sClient); int main() while(1) InitSocket(); ListenToClient(); CloseSocket(); system(del E:test1.A_exp); /system(pause); return 0; /初始化socket库 bool InitSocket() WSADATA wsaData; WORD socketVersion=MAKEWORD(2,2); if(:WSAStartup(socketVersion,&wsaData)!=0) /初始化WinSock服务 printf(Init socket dll errorn); return false; return true; /关闭socket库 bool CloseSocket() /释放winsock库 :WSACleanup(); if(g_pBuff != NULL) delete g_pBuff; g_pBuff = NULL; return true; /解析消息并进行相应的处理 bool ProcessMsg(SOCKET sClient) /从套接口中接收数据,返回copy的字节数 int nRecv = :recv(sClient,g_szBuff,MAX_PACKET_SIZE+1,0); if(nRecv0) g_szBuffnRecv=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 ready to send already exit!n); return false; break; return true; /监听Client消息 void ListenToClient() /创建套接字 SOCKET sListen = :socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if(sListen = SOCKET_ERROR) 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(sClient=:accept(sListen,(sockaddr*)&ClientAddr,&nAddrLen)=INVALID_SOCKET) /解析消息并进行相应的处理 /int count=10;/作为定时当程序执行10s未完成时直接退出 /while(ProcessMsg(sClient)=true&count0) / / Sleep(1000); / count-; / while(ProcessMsg(sClient)=true) Sleep(1000); /关闭同客户端的连接 :closesocket(sClient); :closesocket(sListen); /打开文件 bool OpenFile(CCSDef:TMSG_HEADER* pMsgHeader,SOCKET sClient) CCSDef:TMSG_FILENAME* pRequstFileNameMsg=(CCSDef:TMSG_FILENAME*)pMsgHeader; /对文件名进行处理 char *p1,*p2; for(p1=pRequstFileNameMsg-szFileName,p2=g_szNewFileName;*p1!=0;p1+,p2+) if(*p1!=n) *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) /文件块已经是最后一块 tMsgFile.tFile.nSize = g_lLength - i; else tMsgFile.tFile.nSize = nPacketBufferSize; memcpy(tMsgFile.tFile.szBuff, g_pBuff + tMsgFile.tFile.nStart, tMsgFile.tFile.nSize);/copy到缓冲区 :send(sClient, (char*)(&tMsgFile), sizeof(CCSDef:TMSG_FILE), 0); Sleep(0.5); delete g_pBuff; g_pBuff = NULL; return true; /读取文件进缓冲区 bool ReadFile(SOCKET sClient) if(g_pBuff!=NULL) /如果缓冲区不为空 return true; /打开文件 FILE *pFile; if(pFile = fopen(g_szNewFileName, rb)=NULL) /文件打开失败,发送错误报告 printf(Cannot find the file, request the client input file name againn); 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 = %dn, 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: %sn, tMsgFileName.szFileName); :send(sClient, (char*)(&tMsgFileName), sizeof(CCSDef:TMSG_FILENAME), 0); /分配缓冲区,读取文件内容 g_pBuff = new charg_lLength + 1; if (g_pBuff = NULL) return false; fseek(pFile, 0, SEEK_SET); fread(g_pBuff, sizeof(char), g_lLength, pFile); g_pBuffg_lLength = 0; fclose(pFile); return true; 【2】客户端:头文件同服务器端头文件源程序文件:cpp /*Client.cpp*/ #includeClient.h long g_lLength = 0; char* g_pBuff = NULL; char g_szFileNameMAXFILEDIRLENGTH; char g_szBuffMAX_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() while(1) InitSocket(); ConectToServer(); CloseSocket(); /system(pause); return 0; / 初始化socket库 bool InitSocket() /初始化SOCKET WSADATA wsaData; WORD socketVersion=MAKEWORD(2,2); if(:WSAStartup(socketVersion,&wsaData)!=0) printf(Init socket dll errorn); exit(-1); return true; / 关闭socket库 bool CloseSocket() / 关闭套接字 :closesocket(g_sClient); / 释放winsock库 :WSACleanup(); return true; / 把用户输入的文件路径传送到server端 bool SendFileNameToServer() char szFileNameMAXFILEDIRLENGTH; printf(Input the File Directory: ); /fgets(szFileName, MAXFILEDIRLENGTH, stdin); strcpy(szFileName,E:test1.A_exp); / 把文件路径发到server端 CCSDef:TMSG_FILENAME tMsgRequestFileName; strcpy(tMsgRequestFileName.szFileName, szFileName); if (:send(g_sClient, (char*)(&tMsgRequestFileName), sizeof(CCSDef:TMSG_FILENAME), 0) = SOCKET_ERROR) printf(Send File Name Error!n); exit(-1); return true; / 与server端连接 bool ConectToServer() / 初始化socket套接字 if (g_sClient = :socket(AF_INET, SOCK_STREAM, IPPROTO_TCP) = SOCKET_ERROR) 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 (:connect(g_sClient, (sockaddr*)&servAddr, sizeof(sockaddr_in) = INVALID_SOCKET) printf(Connect to Server Error!n); exit(-1); / 输入文件路径传输到server端 SendFileNameToServer(); / 接收server端传过来的信息,直到保存文件成功为止 while (ProcessMsg() = true) Sleep(1000); return true; / 打开文件失败 bool OpenFileError(CCSDef:TMSG_HEADER *pMsgHeader) if (g_pBuff != NULL)/如果缓冲区内有数据 return true; assert(pMsgHeader != NULL); printf(Cannot find file!n); / 重新输入文件名称 SendFileNameToServer(); return true; / 分配空间以便写入文件 bool AllocateMemoryForFile(CCSDef:TMSG_HEADER *pMsgHeader) assert(pMsgHeader != NULL); if (g_pBuff != NULL) return true; CCSDef:TMSG_FILENAME* pRequestFilenameMsg = (CCSDef:TMSG_FILENAME*)pMsgHeader; printf(File Name: %sn, pRequestFilenameMsg-szFileName); / 把文件的路径设置为D盘根目录下 strcpy(g_szFileName, D:); strcat(g_szFileName, test2.B_imp); /strcat(g_szFileName, pRequestFilenameMsg-szFileName); / 查找相同文件名的文件是否已经存在,如果存在报错退出 FILE* pFile; if (pFile = fopen(g_szFileName, r) != NULL) / 文件已经存在,要求重新输入一个文件 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 charg_lLength + 1; if (g_pBuff != NULL) memset(g_pBuff, 0, g_lLength + 1); printf(Now ready to get the file %s!n, pRequestFilenameMsg-szFileName); CCSDef:TMSG_CLIENT_READY tMsgClientReady; if (:send(g_sClient, (char*)(&tMsgClientReady), sizeof(CCSDef:TMSG_CLIENT_READY), 0) = SOCKET_ERROR) 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(pMsgHeader != NULL); 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 (nStart = 0) printf(Saving file into buffer.n); memcpy(g_pBuff + nStart, pMsgFile-tFile.szBuff, 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 (:send(g_sClient, (char*)(&tMsgSendFileSuccess), sizeof(CCSDef:TMSG_SENDFILESUCCESS), 0) = SOCKET_ERROR) printf(Save the file %s success!n, g_szFileName); return true; else return false; / 处理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 (g_lLength = 0) g_lLength = (CCSDef:TMSG_FILELENGTH*)pMsgHeader)-lLength; printf(File Length: %dn, g_lLength); break; case MSG_FILENAME: / 文件名 return AllocateMemoryForFile(pMsgHeader); break; case MSG_FILE: / 传送文件,写入文件成功之后退出这个函数 www.2cto.com if (WriteToFile(pMsgHeader) /*Sleep(1000);*/ return false; break; return true;
展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > 模板表格


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!