`
yangshen998
  • 浏览: 1288884 次
文章分类
社区版块
存档分类
最新评论

socket实现大型文件传输 .

 
阅读更多

最近需要做网络传输的项目,需要实现较大文件的传输。在网上收集了不少资料,但是各有各的做法,尤其是关于文件自动接收这一块不太清楚。 经过图书馆查阅后还是找到了一种解决办法,虽然做的不太专业,但是思路比较精简、清晰,也希望能给大家尤其是刚学习socket套接字的人一些启示。

                               

   对于套接字socket我其实也不太懂,并且一般资料都可以查找到,所以不交易累赘了,直接说如何实现文件的传输吧。

    对于发送文件,有三步:发送文件长度,发送文件名,发送文件内容。 

    关于发送文件内容,又可以根据文件大小进行直接传输和分块传输,如果是分块传输还需要多线程,否则会容易使程序失去响应。 在这里其实我也有一个疑惑,就是通过CFileDialog类GetFileName函数获取文件名,一般没有问题,但是当文件名很长(如大于60)时不能完整读取,导致接收方无法判别文件类型。 所以保险起见,我就从GetFilePath中截取出了文件名。

 

  1. void CChatDlg::OnSend()   
  2. {  
  3.     if(flag==-1)  
  4.     {  
  5.         MessageBox("处于未连接状态");  
  6.         return;  
  7.     }  
  8.       
  9.     CFileDialog  dlg(TRUE);  
  10.     dlg.m_ofn.lpstrTitle="选择图片";  
  11.     dlg.m_ofn.lpstrFilter="All Files";  
  12.     CString path="";  
  13.     CString name="";  
  14.     if(dlg.DoModal()==IDOK)  
  15.     {  
  16.         path=dlg.GetPathName();//获取文件路径名   
  17.         //name=dlg.GetFileName();//获取文件名   
  18.     }  
  19.     if(path=="")  
  20.         return ;//表示没有选择任何元素   
  21.   
  22.      //不直接读取文件名,而是从路径名中截取   
  23.     int pos=0,start=0;  
  24.     while(1)  
  25.     {  
  26.         start=pos;  
  27.         pos=path.Find('\\',start+1);  
  28.         if(pos<0)  
  29.             break;  
  30.     }  
  31.     name=path.Right(path.GetLength()-start-1);  
  32.     file.Open(path,CFile::modeRead);//打开文件   
  33.      dwlen=file.GetLength();//获取文件长度   
  34.     m_se.SetRange32(0,dwlen);  
  35.     CString te;  
  36.     te.Format("%d",dwlen);  
  37.     if(flag==0)//发送图片数据   
  38.         send(m_accept, te.GetBuffer(0), 10, 0);//发送文件的长度   
  39.     if(flag==1)  
  40.         send(m_local, te.GetBuffer(0), 10, 0);  
  41.     Sleep(500);//延时   
  42.       
  43.     if(flag==0)//发送图片数据   
  44.         send(m_accept, name.GetBuffer(0), name.GetLength(), 0);//发送文件的名   
  45.     if(flag==1)  
  46.         send(m_local, name.GetBuffer(0), name.GetLength(), 0);  
  47.     Sleep(500);//延时   
  48.       
  49.       
  50.     if(dwlen<=1024*1024)//如果小于1M就直接传输   
  51.     {  
  52.         if(date!=NULL)  
  53.         {  
  54.             delete []date;  
  55.             date=NULL;  
  56.         }  
  57.         date=new char[dwlen];//开辟neicun   
  58.         memset(date,0,dwlen);//初始化   
  59.         file.Read(date,dwlen);//读取文件   
  60.         file.Close();  
  61.         int n=0;  
  62.         if(flag==0)//发送图片数据   
  63.             n=send(m_accept, date, dwlen, 0);  
  64.         if(flag==1)  
  65.             n=send(m_local, date, dwlen, 0);  
  66.         m_se.SetPos(n);  
  67.         CString ss;  
  68.         ss.Format("%d   %d",dwlen,n);    
  69.         ss+="发送完成";  
  70.         MessageBox(ss);  
  71.         delete []date;  
  72.         date=NULL;  
  73.     }  
  74.     else  
  75.     {  
  76.        //需要选择多线程,创建一个线程   
  77.         p_thread=AfxBeginThread(SEND,this,0,0,0,NULL);//开启一个线程   
  78.     }     
  79. }  


    注解中的什么图片的是错误的,是可以传输任意格式的文件的。大家可以看到我提取文件名的过程繁琐,原因我

 

上面一段已经说明了,也希望大家更好的解决方法。其中flag的值时表示是服务端还是客户端,0-服务端,1-客户端,集合在了一个程序中。  

     注意::: 其中的Sleep(500)的延时是因为为了让接受方有足够多的时间获取文件长度和文件名关键信息,如果不延时,接收方会先接受到文件内容后接收到文件长度和文件名,顺序是相反的,具体原因我也没弄清楚,希望大家指教。

      最后是关于一个线程的函数,具体如下:

 

  1. UINT SEND(LPVOID pThreadParam)//线程函数   
  2. {  
  3.     CChatDlg *dlg=(CChatDlg *)pThreadParam;  
  4.     if(date!=NULL)  
  5.         {  
  6.             delete []date;  
  7.             date=NULL;  
  8.         }  
  9.         int total=0,len=0;  
  10.         while(total<dwlen)//直到全部发送完成   
  11.         {   
  12.                 if(dwlen-total>=1024*100)  
  13.                 {  
  14.                    date=new char[1024*100];  
  15.                    memset(date,0,1024*100);  
  16.                    file.Read(date,1024*100);  
  17.                    if(dlg->flag==0)//发送数据   
  18.                     len=send(dlg->m_accept, date, 1024*100, 0);  
  19.                 if(dlg->flag==1)  
  20.                     len=send(dlg->m_local, date, 1024*100, 0);  
  21.                 }  
  22.                 else  
  23.                 {  
  24.                     date=new char[dwlen-total];  
  25.                      memset(date,0,dwlen-total);  
  26.                     file.Read(date,dwlen-total);  
  27.                     if(dlg->flag==0)//发送数据   
  28.                     len=send(dlg->m_accept, date, dwlen-total, 0);  
  29.                     if(dlg->flag==1)  
  30.                     len=send(dlg->m_local, date, dwlen-total, 0);  
  31.                 }  
  32.             Sleep(1);  
  33.             total+=len;//累计已经发送的数据   
  34.             dlg->m_se.SetPos(total);  
  35.             delete []date;  
  36.             date=NULL; //回收内存空间   
  37.         }  
  38.         file.Close();  
  39.         CString ss;  
  40.         ss.Format("%d",total);    
  41.         ss+="发送完成";  
  42.         MessageBox(dlg->m_hWnd,ss,"提示",MB_OK);  
  43.            
  44.         DWORD exit=0;  
  45.    
  46.         BOOL ret=GetExitCodeThread(dlg->p_thread->m_hThread,&exit);//获取线程退出代码   
  47.         if(exit==STILL_ACTIVE) //如果进程仍在进行   
  48.         {  
  49.             dlg->p_thread->ExitInstance();//退出进程   
  50.             dlg->p_thread=NULL;  
  51.         }  
  52.       
  53.     return 0;  
  54. }  


   线程的好处是不会让程序失去响应,而且对于大型文件传输来说这是必须的。

 

    其次,关于文件的接受,就是一个注册的OnSocket中的FD_READ,通过这个方式设置WSAAsyncSelect模型的。

 

  1. int nRet = WSAAsyncSelect(m_local, m_hWnd, WM_SOCKET, FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE);  
  2.     if (nRet != 0)  
  3.     {  
  4.         TRACE("设置WSAAsyncSelect模型失败");  
  5.     }  
  6.       

    关于OnSocket 函数完整如下,处理FD_READ|FD_CONNECT|FD_ACCEPT等消息

 

 

  1. void CChatDlg::OnSocket(WPARAM wParam,LPARAM lParam)  
  2. {  
  3.     int nError = WSAGETSELECTERROR(lParam);     //读取错误代码   
  4.     int nEvent = WSAGETSELECTEVENT(lParam);     //读取网络事件   
  5.     SOCKET sock = wParam;  
  6.     switch (nEvent)   
  7.     {  
  8.     case FD_ACCEPT:  
  9.         {  
  10.             //接收客户端的连接   
  11.             closesocket(m_accept);  
  12.             sockaddr_in sockAddr;  
  13.             int nAddrSize = sizeof(sockaddr_in);  
  14.             m_accept = accept(sock, (sockaddr*)&sockAddr, &nAddrSize);  
  15.             WSAAsyncSelect(m_accept, m_hWnd, WM_SOCKET, FD_CLOSE|FD_READ);  
  16.             state=true;  
  17.             flag=0; //表示作为服务器   
  18.             m_connect.EnableWindow(FALSE);//由于被连接,需要是连接功能丧失   
  19.             break;  
  20.         }  
  21.     case FD_READ:   //接收数据   
  22.         {  
  23.             switch(flag1)  
  24.             {  
  25.             case 1:  
  26.                 memset(buffer,0,10);  
  27.                 recv(sock, buffer, 10, 0);//这个语句用于接收文件的长   
  28.                    m_length=atoi(buffer);  
  29.                    UpdateData(false);  
  30.                    flag1=2;  //做接下来一步   
  31.                    m_get.SetRange32(0,m_length); //设置接受进度条的范围   
  32.                    break;  
  33.             case 2: recv(sock, filename, 200, 0); //接受文件名   
  34.                 flag1=3;//做接下来一步   
  35.                 f.Open(filename,CFile::modeCreate|CFile::modeWrite);//创建一个文件   
  36.                 break;  
  37.             case 3:if(temp!=NULL)  
  38.                    {  
  39.                        delete [] temp;  
  40.                        temp=NULL;  
  41.                    }  
  42.                 temp=new char[1024*56];//开辟一个内存   
  43.                 memset(temp,0,1024*56);  
  44.                 x=recv(sock,temp,1024*56,0);  
  45.                 f.Write(temp,x);  
  46.                 total+=x;  
  47.                 m_get.SetPos(total);  
  48.                 delete []temp;  
  49.                 temp=NULL;  
  50.                 if(total>=m_length)//表示接受完成   
  51.                 {  
  52.                     f.Close();  
  53.                     memset(filename,0,200);  
  54.                     flag1=1;  
  55.                   CString sd; sd.Format("%d",total);sd+="接受完成";  
  56.                   MessageBox(sd);  
  57.                   total=x=0;  
  58.                 }  
  59.                 break;  
  60.             }  
  61.         }  
  62.         break;  
  63.     case FD_CLOSE:  
  64.         {  
  65.             if(flag==0)  
  66.                 closesocket(m_accept);  
  67.             state= FALSE;  
  68.             flag=-1;  
  69.             m_connect.EnableWindow(TRUE);//是连接功能恢复正常   
  70.             break;  
  71.         }  
  72.     case FD_CONNECT:                            //连接网络事件   
  73.         {  
  74.             if(nError == 0)                     //连接成功   
  75.             {  
  76.                 state= TRUE;  
  77.                 flag=1;//表示作为客户端   
  78.                 MessageBox("连接成功");  
  79.             }  
  80.             break;  
  81.         }  
  82.           
  83.     }     
  84. }  


     其中接受就在FD_READ消息中,flag1-1接受文件长度,flag1-2接受文件名,flag1-3接受文件内容。

 

     当然整个函数太长了,本来应该一些语句应该设置成一些函数的,那样也更直观。

     这基本上是这个工程的全部了,还是比较简洁的。在同一台电脑上测试结果是:732577734字节共耗时114秒,平均6.12M/s,也不是体太慢。

       整个项目还是有不少弊端的,有疑惑的可以相互交流讨论。

    完整工程下载地址:

    http://download.csdn.net/detail/jin123wang/3937052

2
0
分享到:
评论

相关推荐

    安卓Android源码——Android中Socket大文件断点上传.zip

    通过以上步骤,可以在Android应用中实现大文件的断点续传功能,保证文件传输的可靠性。在实际开发中,还需要结合具体的业务需求,对代码进行优化和调整,以提供更好的用户体验。在压缩包中的`AndroidSocket`文件可能...

    SuperSocket.ClientEngine.QuickStart.zip

    文件列表中的"SuperSocket.ClientEngine.QuickStart-master"表示这是一个Git仓库的主分支,可能包含了源代码、配置文件和说明文档等资源。 要运行这个示例,你需要在Visual Studio环境下打开项目,然后使用NuGet包...

    socket_file_transfer.rar_socket 文件

    在本示例中,"socket_file_transfer.rar_socket 文件"是一个关于使用Socket进行文件传输的项目,可能包含一个或多个源代码文件。描述提到"单线程socket文件传输,直接cc -o 生成可执行文件",这意味着这个程序是用C...

    liunx上socket C++编程(可以实现图片、文件传输)

    在Linux系统中,Socket编程是实现网络通信的基础,它提供了进程间通信的一种接口。C++结合Socket编程可以创建跨平台的文件和数据传输应用。在这个主题中,我们将深入探讨如何在Linux环境下使用C++进行Socket编程,...

    基于Socket的大型文件传输系统的设计与实现-开题报告

    ### 基于Socket的大型文件传输系统的设计与实现 #### 一、项目背景与目的意义 当前,随着网络通信技术的快速发展与用户需求的多样化,网络环境正在经历一场深刻的变革与发展。在这种背景下,开发一个既简单又实用...

    HP-Socket通信框架 v6.0.1.zip

    7. **负载均衡与集群**:对于大型分布式系统,HP-Socket可能支持负载均衡策略,将客户端请求分发到不同的服务器,降低单点压力。同时,它可以与其他服务器组成集群,增强系统的可用性和扩展性。 8. **监控与日志**...

    Java基于Socket文件传输示例

    在Java编程中,Socket通信是一种基础且重要的网络编程模型,常用于实现客户端与服务器之间的数据交互,包括文件传输。在这个示例中,我们将探讨如何利用Java的Socket API进行文件的发送与接收。以下是对"Java基于...

    前端项目-socket.io-stream.zip

    Socket.IO-Stream是Socket.IO的一个扩展,它将Node.js的Stream接口与Socket.IO连接相结合,使得通过WebSocket传输大量数据变得更加简单和高效,尤其适用于文件上传、实时音频/视频流或者大型游戏等场景。 **Socket....

    C# Socket 发送接收文件,消息

    在IT行业中,网络通信是至关重要的,特别是在分布式系统和客户端-服务器架构中。C#作为.NET框架的主要...总的来说,C#的Socket提供了一套完整的工具,能够实现高效的文件传输和消息交换,是开发网络应用的重要基础。

    Android socket上传大文件client + server

    "Android socket上传大文件client + server"这个项目就是针对这种情况设计的,它通过自定义的TCP通信协议实现了大文件的分块传输,支持断点续传,以确保文件传输的稳定性和效率。 首先,我们来看一下Socket通信的...

    C# SOCKET加密文件消息传输通信

    此外,对于大型文件传输,可能需要考虑使用缓冲技术,提高传输效率。 总结来说,“C# SOCKET加密文件消息传输通信”涉及了网络编程、数据加密、文件操作等多个重要知识点,对于开发安全、可靠的网络应用具有重要...

    多线程socket文件传输_支持断点续传_收发消息_点对多点

    总的来说,多线程Socket文件传输技术结合了多线程的并行处理能力、Socket的网络通信功能、断点续传的可靠性以及点对多点的高效性,为大型文件传输和复杂的网络应用场景提供了强大的解决方案。在VC++环境中,开发者...

    socket做的支持多线程断点上传or断点续传Java源码

    这是一个高级的网络编程任务,通常在大型文件传输或者云存储服务中常见。 断点上传和断点续传是解决大文件传输中断问题的关键技术。当上传或下载大文件时,如果网络连接中断,常规方式会需要从头开始重新传输。而...

    socket局域网文件传输

    在局域网环境中,利用Socket实现文件传输是常见的需求,尤其在C#编程中,我们可以利用.NET Framework提供的丰富的API来构建这样的系统。本文将详细讲解如何使用C#进行Socket局域网文件传输。 首先,我们需要理解...

    socket UDP/TCP 文件传输 VC

    在文件传输中,TCP通常用于需要高度可靠性的场景,如大型文件的传输,因为它可以检测并重传丢失的数据包。而UDP常用于实时应用,如在线视频或音频流,对数据丢失有一定的容忍度,追求速度而非完整性。 在VC中,使用...

    安卓Android源码——基于socket通讯的文件续传!.zip

    本项目的核心是利用Socket编程实现设备间的文件传输,并支持断点续传,以提高文件传输的稳定性和效率。 首先,让我们了解什么是Socket。Socket是网络通信的基本组件,它提供了应用程序与网络协议之间的接口。在...

    socket-php文件分段上传

    总之,“socket-php文件分段上传”技术是解决大文件上传的有效方案,它利用了Socket通信的灵活性和HTML5的File API,实现了高效、可靠的文件传输。对于开发大型、高并发的Web应用,尤其是涉及到大量文件操作的场景,...

    大型文件传输

    本项目提供的就是一个自编写的大型文件传输实例,通过使用多线程和套接字(Socket)技术,实现了高效稳定的局域网文件传输,速度达到了6.2MB/s。 首先,我们来探讨文件传输的基本原理。文件传输通常涉及到两个主要...

    Java_Socket_UDP_2.zip_udp java 服务

    在实现UDP服务时,需要权衡这些因素,尤其是在设计大型分布式系统或涉及敏感信息传输时。 9. **性能优化**: 在使用UDP时,可以通过合理设置数据报包大小、避免不必要的数据复制、使用缓冲池等方式来优化性能。 ...

    基于QT的Network模块的QTcpServer和QTcpSocket,进行网络的文件传输 可传输大型文件如Dicom数据等

    本篇将详细讲解如何使用QT的Network模块中的QTcpServer和QTcpSocket来实现网络文件传输,特别是针对大型文件,如Dicom数据。 首先,QTcpServer是QT中的一个类,它允许我们创建一个服务器端点,等待来自网络的连接...

Global site tag (gtag.js) - Google Analytics