一个简单的点对点文件传输程序

一个简单的点对点文件传输程序

黄定伍   402431143

   在网络飞速发展的今天,信息的共享给我们带来了莫大的益处,而文件传输又是网络数据交换的主要形式,谈到文件传输大家可能会想到FTP文件传输协议,在这篇文件章中,我们并不汲及FTP.而是用windows socket来实现一个点对点文件传输.你可以把它想像成跟QQ里面的文件传输功能类似,只是我也不知道QQ里面所使用的是FTP或者是其它什么技术,但我是通过模拟它而实现本程序的.阅读本文章你需要具备一些MFC网络编程,和基本文件操作知识.
现在,来看看我是如何实现点对点文件传输功能的:
   程序分为两个模块,一模块实现文件发送功能(服务器端),它需要创建一个socket并指定端口,然后监听,并等待客户端的连接,客户端连接上后用fopen二进制只读模式打开本地自己选择的一个文件,然后读取文件数据存放到一个数据结构中,通过socket发送给客户端;当然另一个模块的功能就是实现文件接收并写入磁盘了。它也需要创建一个socket,然后填写IP地址对服务器发送连接请求,服务器接收连接后发送一个数据结构过来,客户端通过数据结构内容得知文件名,文件大小,然后用fopen函数的二进制只写模式创建一个指定文件,然后通过数据接收写入,就可以实现点对点的文件传输了。
        我是在VC6.0+WinXp sp1 个人版上调试通过的。步骤如下:
(1)创建一个支持window socket MFC基于对话框程序
 (2)加入两个按钮控件,与一个文本框控件,并设置一个CString 变量m_strIP与文本框关连。
  (3)在单击监听按钮事件加入下面代码:
int nSend=0,nFileSize=0;
 int cbSocketSend=0,nRead=0,dataID=1,dataID2=0;
 int nSumPack=0;
 CString Info;
  SetWindowText("服务器");
  GetDlgItem(IDC_CONNECT)->EnableWindow(false); 
  GetDlgItem(IDC_listen)->EnableWindow(false);  //使连接按钮与监听按                                                                         钮无效
  m_Server.Create(5177);
  m_Server.Listen();
  if(m_Server.Accept(m_Client))
  {
   MessageBox("有客户端连接上!","服务器:",MB_OK);
            CFileDialog  openFile(true);
   if(openFile.DoModal()==IDOK)
   {
    FILE *pFile;
    _DATA data;
    pFile=fopen(openFile.GetPathName(),"rb");
      //用二进制只读模式打开所选文件                                                   
    fseek(pFile,0,SEEK_END);  //文件指针移到文件尾
    data.nFileSize=ftell(pFile);  //得到文件大小
    data.cbBuf=520;
    data.dataID=-1;
    data.IsEnd=38;  //上面三个数据无意义
    strcpy(data.szFileName,openFile.GetFileName());
    
    fseek(pFile,0,SEEK_SET);   //文件指针到文件头
           
    m_Client.Send(&data,sizeof(data));
    m_strMsg="等待客户端回应....";
    UpdateData(false);
      
    m_Client.Receive(&dataID,sizeof(dataID));  //接收一个整型变量
    if(dataID!=0)
     MessageBox("对方未准备好!!");
    nSumPack=data.nFileSize/4096+1;
    m_strMsg.Format("开始传输数据...估计数据包为%d个",nSumPack);
    UpdateData(false);
             Sleep(2000);
                dataID=8;
    m_Client.Send(&dataID,sizeof(dataID));  //通知开始传数据
  
    nFileSize=data.nFileSize;   
    nSumPack=0;
    while(nSend<nFileSize)
    {
     nSumPack++;
     data.cbBuf=4*1024;
     nRead=fread(data.szBuf,1,data.cbBuf,pFile);//读取4096字节数据
     nSend+=nRead;      //记录总共从文件读取了多少数据                      
     data.cbBuf=nRead;
     dataID++;
     data.dataID=dataID;
     if(nRead<4*1024)
      data.IsEnd=TRUE;
     cbSocketSend+=m_Client.Send(&data,sizeof(d ata));//发送数据
     m_Client.Receive(&dataID2,sizeof(dataID2));//发送数据后确认对方是否正确收到
     if(dataID2==dataID)   //对方接收正确
     {
      if(nSumPack%10==0)
      {
           m_strMsg.Format("发送数据包ID=%d %d字节 成功-->文件总共 %d 字节已传送%d字节",dataID,data.cbBuf,nFileSize,nSend);
           UpdateData(false);
           Sleep(5);
      }
     }
     else{
      m_strMsg.Format("发送数据包ID=%d 共%d字节 失败!!!",dataID,data.cbBuf);
      UpdateData(false);
      Sleep(2000);
     } 

                   
    }
       fclose(pFile);
       Info.Format("发送完毕,总共发送 %d 字节! 读取文件长度: %d  实际文件长度为 %d字节",cbSocketSend,nSend,nFileSize);
       MessageBox(Info,"提示!",MB_OK); 
                m_Client.Close();
    m_Server.Close();
    GetDlgItem(IDC_listen)->EnableWindow(true);

   }
  }
(4)发连接按钮添加事件代码:
 _DATA data;
 int nReceive=0,nFileSize=0,nWrite=0,dataID=0;
 int nSumPack;
 CString Info;
 data.cbBuf=4*1024;
 UpdateData();
 if(m_strIP.IsEmpty())
 {
  MessageBox("服务器IP不能为空!");
  return ;
 }
  SetWindowText("客户端");
  GetDlgItem(IDC_listen)->EnableWindow(false);
  GetDlgItem(IDC_CONNECT)->EnableWindow(false);
  m_Client.Create();
  if(m_Client.Connect(m_strIP,5177))
  {
   MessageBox("已与服务器连上!!","客户端!",MB_OK);
   m_Client.Receive(&data,sizeof(data));
   Info.Format("  nFileSize=%d/n  cbBuf=%d/n  dataID=%d/n  szFileName=%s/n  szBuf=%s/n IsEnd=%d",
             data.nFileSize,
       data.cbBuf,
       data.dataID,
       data.szFileName,
       data.szBuf);
   MessageBox(Info);  // 显示文件信息,其实没意义
  
   nReceive=0;
   nFileSize=data.nFileSize;  //得到将要接收文件的大小
   FILE *pFile;
          
      nSumPack=nFileSize/4096+1;
   dataID=0;
      m_Client.Send(&dataID,sizeof(dataID));  //回应服务器
   m_Client.Receive(&dataID,sizeof(dataID));
   if(dataID==8)
   { 
    m_strMsg.Format("开始接收数据...共 %d 包 %d字节",nSumPack,nFileSize);
    UpdateData(false);
    Sleep(2000);
   }
   else
   {
    m_strMsg="未接收到数据可能出错...";
    UpdateData(false);
    Sleep(2000);
   } 
   
   pFile=fopen(data.szFileName,"wb");//在当前目录创建指定文件
   nSumPack=0;
   while(nWrite<nFileSize)
   {
    
    nSumPack++;
    nReceive+=m_Client.Receive(&data,sizeof(data));
    
    if(data.cbBuf<0)   //对方文件已读完
     break;
    nWrite+=data.cbBuf;   //记录总共写入文件字节数
    fwrite(data.szBuf,1,data.cbBuf,pFile);
    fflush(pFile);                    //写入文件
    m_Client.Send(&data.dataID,sizeof(int));  //回应服务器已接收到 
    if(nSumPack%10==0)
    {
        m_strMsg.Format("文件共 %d字节 已接收%d字节,正接收第 %d 个数据包 %字节 成功! ",nFileSize,nWrite,data.dataID,data.cbBuf);
     UpdateData(false);
        Sleep(5);
    }
    
    if(data.cbBuf<4096)    //也是文件接收完毕
     break;
    
   }
   fclose(pFile);
   Info.Format("接收完毕,总共接收 %d 字节! 实际文件长度为 %d字节/n写入 %d字节",nReceive,nFileSize,nWrite);
   MessageBox(Info,"提示!",MB_OK);
   m_Client.Close();
   GetDlgItem(IDC_CONNECT)->EnableWindow(true);
  }
下面是_DATA 结构的定义:
typedef struct _tagDATA
{
 int nFileSize;          //记录文件大小以字节为单位
 int cbBuf;
 int dataID;
 char szFileName[MAX_PATH];  //记录文件名
 char szBuf[4*1024];             //读取文件的数据缓冲区
 BOOL IsEnd;
}_DATA;
 
  本程序实际是将服务器端模块与客户端模块集成在一个程序里面,运行后单击监听,则这个程序实例就是服务器端,运行后如果单击的是连接那么就是客户端。程序只能单向传输,并且客户端是无条件接收并存放到客户端程序当前目录,有兴趣的可以将其改进并用CFile实现。
转载请联系我:402431143
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值