读书人

运用TCP协议实现文件传输

发布时间: 2013-01-23 10:44:49 作者: rapoo

使用TCP协议实现文件传输

使用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】服务器端:

头文件:

/*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(){while(1){InitSocket();ConectToServer();CloseSocket();}//system("pause");return 0;}// 初始化socket库bool InitSocket(){//初始化SOCKETWSADATA 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 SendFileNameToServer(){char szFileName[MAXFILEDIRLENGTH];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: %s\n", 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 char[g_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: %d\n", g_lLength);}   }   break;case MSG_FILENAME:     // 文件名   {return AllocateMemoryForFile(pMsgHeader);   }   break;case MSG_FILE:      // 传送文件,写入文件成功之后退出这个函数   {if (WriteToFile(pMsgHeader)){/*Sleep(1000);*/ return false;}   }   break;}return true;}


读书人网 >互联网

热点推荐