1. 程式人生 > >socket實現大型檔案傳輸

socket實現大型檔案傳輸

       最近需要做網路傳輸的專案,需要實現較大檔案的傳輸。在網上收集了不少資料,但是各有各的做法,尤其是關於檔案自動接收這一塊不太清楚。 經過圖書館查閱後還是找到了一種解決辦法,雖然做的不太專業,但是思路比較精簡、清晰,也希望能給大家尤其是剛學習socket套接字的人一些啟示。

                               

   對於套接字socket我其實也不太懂,並且一般資料都可以查詢到,所以不交易累贅了,直接說如何實現檔案的傳輸吧。

    對於傳送檔案,有三步:傳送檔案長度,傳送檔名,傳送檔案內容。 

    關於傳送檔案內容,又可以根據檔案大小進行直接傳輸和分塊傳輸,如果是分塊傳輸還需要多執行緒,否則會容易使程式失去響應。 在這裡其實我也有一個疑惑,就是通過CFileDialog類GetFileName函式獲取檔名,一般沒有問題,但是當檔名很長(如大於60)時不能完整讀取,導致接收方無法判別檔案型別。 所以保險起見,我就從GetFilePath中截取出了檔名。

void CChatDlg::OnSend() 
{
	if(flag==-1)
	{
		MessageBox("處於未連線狀態");
		return;
	}
	
	CFileDialog	 dlg(TRUE);
	dlg.m_ofn.lpstrTitle="選擇圖片";
	dlg.m_ofn.lpstrFilter="All Files";
	CString path="";
	CString name="";
	if(dlg.DoModal()==IDOK)
	{
		path=dlg.GetPathName();//獲取檔案路徑名
		//name=dlg.GetFileName();//獲取檔名
	}
	if(path=="")
		return ;//表示沒有選擇任何元素

	 //不直接讀取檔名,而是從路徑名中擷取
	int pos=0,start=0;
	while(1)
	{
		start=pos;
		pos=path.Find('\\',start+1);
		if(pos<0)
			break;
	}
	name=path.Right(path.GetLength()-start-1);
	file.Open(path,CFile::modeRead);//開啟檔案
	 dwlen=file.GetLength();//獲取檔案長度
	m_se.SetRange32(0,dwlen);
	CString te;
	te.Format("%d",dwlen);
	if(flag==0)//傳送圖片資料
		send(m_accept, te.GetBuffer(0), 10, 0);//傳送檔案的長度
	if(flag==1)
		send(m_local, te.GetBuffer(0), 10, 0);
	Sleep(500);//延時
	
	if(flag==0)//傳送圖片資料
		send(m_accept, name.GetBuffer(0), name.GetLength(), 0);//傳送檔案的名
	if(flag==1)
		send(m_local, name.GetBuffer(0), name.GetLength(), 0);
	Sleep(500);//延時
	
	
	if(dwlen<=1024*1024)//如果小於1M就直接傳輸
	{
		if(date!=NULL)
		{
			delete []date;
			date=NULL;
		}
		date=new char[dwlen];//開闢neicun
		memset(date,0,dwlen);//初始化
		file.Read(date,dwlen);//讀取檔案
		file.Close();
		int n=0;
		if(flag==0)//傳送圖片資料
			n=send(m_accept, date, dwlen, 0);
		if(flag==1)
			n=send(m_local, date, dwlen, 0);
		m_se.SetPos(n);
		CString ss;
		ss.Format("%d   %d",dwlen,n);  
		ss+="傳送完成";
		MessageBox(ss);
		delete []date;
		date=NULL;
	}
	else
	{
	   //需要選擇多執行緒,建立一個執行緒
		p_thread=AfxBeginThread(SEND,this,0,0,0,NULL);//開啟一個執行緒
	}	
}

    註解中的什麼圖片的是錯誤的,是可以傳輸任意格式的檔案的。大家可以看到我提取檔名的過程繁瑣,原因我

上面一段已經說明了,也希望大家更好的解決方法。其中flag的值時表示是服務端還是客戶端,0-服務端,1-客戶端,集合在了一個程式中。  

     注意::: 其中的Sleep(500)的延時是因為為了讓接受方有足夠多的時間獲取檔案長度和檔名關鍵資訊,如果不延時,接收方會先接受到檔案內容後接收到檔案長度和檔名,順序是相反的,具體原因我也沒弄清楚,希望大家指教。

      最後是關於一個執行緒的函式,具體如下:

UINT SEND(LPVOID pThreadParam)//執行緒函式
{
	CChatDlg *dlg=(CChatDlg *)pThreadParam;
	if(date!=NULL)
		{
			delete []date;
			date=NULL;
		}
		int total=0,len=0;
		while(total<dwlen)//直到全部發送完成
		{ 
				if(dwlen-total>=1024*100)
				{
				   date=new char[1024*100];
				   memset(date,0,1024*100);
				   file.Read(date,1024*100);
				   if(dlg->flag==0)//傳送資料
					len=send(dlg->m_accept, date, 1024*100, 0);
				if(dlg->flag==1)
					len=send(dlg->m_local, date, 1024*100, 0);
				}
				else
				{
					date=new char[dwlen-total];
				     memset(date,0,dwlen-total);
					file.Read(date,dwlen-total);
					if(dlg->flag==0)//傳送資料
					len=send(dlg->m_accept, date, dwlen-total, 0);
				    if(dlg->flag==1)
					len=send(dlg->m_local, date, dwlen-total, 0);
				}
		    Sleep(1);
		   	total+=len;//累計已經發送的資料
			dlg->m_se.SetPos(total);
			delete []date;
			date=NULL; //回收記憶體空間
		}
		file.Close();
		CString ss;
		ss.Format("%d",total);  
		ss+="傳送完成";
		MessageBox(dlg->m_hWnd,ss,"提示",MB_OK);
		 
        DWORD exit=0;
 
		BOOL ret=GetExitCodeThread(dlg->p_thread->m_hThread,&exit);//獲取執行緒退出程式碼
		if(exit==STILL_ACTIVE) //如果程序仍在進行
		{
			dlg->p_thread->ExitInstance();//退出程序
			dlg->p_thread=NULL;
		}
	
	return 0;
}

   執行緒的好處是不會讓程式失去響應,而且對於大型檔案傳輸來說這是必須的。

    其次,關於檔案的接受,就是一個註冊的OnSocket中的FD_READ,通過這個方式設定WSAAsyncSelect模型的。

int nRet = WSAAsyncSelect(m_local, m_hWnd, WM_SOCKET, FD_ACCEPT|FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE);
	if (nRet != 0)
	{
		TRACE("設定WSAAsyncSelect模型失敗");
	}
	
    關於OnSocket 函式完整如下,處理FD_READ|FD_CONNECT|FD_ACCEPT等訊息
void CChatDlg::OnSocket(WPARAM wParam,LPARAM lParam)
{
	int nError = WSAGETSELECTERROR(lParam);		//讀取錯誤程式碼
	int nEvent = WSAGETSELECTEVENT(lParam);		//讀取網路事件
	SOCKET sock = wParam;
	switch (nEvent) 
	{
	case FD_ACCEPT:
		{
			//接收客戶端的連線
			closesocket(m_accept);
			sockaddr_in sockAddr;
			int nAddrSize = sizeof(sockaddr_in);
			m_accept = accept(sock, (sockaddr*)&sockAddr, &nAddrSize);
			WSAAsyncSelect(m_accept, m_hWnd, WM_SOCKET, FD_CLOSE|FD_READ);
			state=true;
			flag=0; //表示作為伺服器
			m_connect.EnableWindow(FALSE);//由於被連線,需要是連線功能喪失
			break;
		}
	case FD_READ:	//接收資料
		{
			switch(flag1)
			{
			case 1:
				memset(buffer,0,10);
				recv(sock, buffer, 10, 0);//這個語句用於接收檔案的長
	               m_length=atoi(buffer);
				   UpdateData(false);
				   flag1=2;  //做接下來一步
				   m_get.SetRange32(0,m_length); //設定接受進度條的範圍
				   break;
			case 2: recv(sock, filename, 200, 0); //接受檔名
				flag1=3;//做接下來一步
				f.Open(filename,CFile::modeCreate|CFile::modeWrite);//建立一個檔案
				break;
			case 3:if(temp!=NULL)
				   {
					   delete [] temp;
					   temp=NULL;
				   }
				temp=new char[1024*56];//開闢一個記憶體
				memset(temp,0,1024*56);
				x=recv(sock,temp,1024*56,0);
				f.Write(temp,x);
			    total+=x;
				m_get.SetPos(total);
				delete []temp;
				temp=NULL;
				if(total>=m_length)//表示接受完成
				{
					f.Close();
					memset(filename,0,200);
					flag1=1;
				  CString sd; sd.Format("%d",total);sd+="接受完成";
				  MessageBox(sd);
				  total=x=0;
				}
				break;
			}
		}
		break;
	case FD_CLOSE:
		{
			if(flag==0)
				closesocket(m_accept);
			state= FALSE;
			flag=-1;
			m_connect.EnableWindow(TRUE);//是連線功能恢復正常
			break;
		}
	case FD_CONNECT:							//連線網路事件
		{
			if(nError == 0)						//連線成功
			{
				state= TRUE;
				flag=1;//表示作為客戶端
				MessageBox("連線成功");
			}
			break;
		}
		
	}	
}

     其中接受就在FD_READ訊息中,flag1-1接受檔案長度,flag1-2接受檔名,flag1-3接受檔案內容。

     當然整個函式太長了,本來應該一些語句應該設定成一些函式的,那樣也更直觀。

     這基本上是這個工程的全部了,還是比較簡潔的。在同一臺電腦上測試結果是:732577734位元組共耗時114秒,平均6.12M/s,也不是體太慢。

       整個專案還是有不少弊端的,有疑惑的可以相互交流討論。

    完整工程下載地址:

相關推薦

socket實現大型檔案傳輸

       最近需要做網路傳輸的專案,需要實現較大檔案的傳輸。在網上收集了不少資料,但是各有各的做法,尤其是關於檔案自動接收這一塊不太清楚。 經過圖書館查閱後還是找到了一種解決辦法,雖然做的不太專業,但是思路比較精簡、清晰,也希望能給大家尤其是剛學習socket套接字的人

python基於併發與socket實現遠端檔案傳輸程式

FTP程式 Client: * bin/start.py 程式入口 * conf/配置檔案存放 * core/ * auth.py 登陸,註冊以及上傳下載檢視當前資料夾下檔案以及刪除功能存放 * cline.py 與服務端通訊 * home 本地使用者目錄 Server: * bin/

C#實戰027:socket實現檔案傳輸

前面寫了一個單檔案傳輸的,後來發現當傳送的檔案大於設定的快取空間時,檔案就會出現丟包的現象,導致檔案無法使用,所以為了適應大檔案的傳輸,這裡我將程式碼進行了下修改,實現大檔案傳輸。 不過socket實現大檔案傳輸有個缺點,由於傳輸過程是通過位元組快取傳送,接受也是讀寫位元組,導致整個傳輸過

C#實戰026:socket實現檔案傳輸

    實現簡單的資訊通訊,接下來我們要繼續來是實現檔案的傳輸,同樣這次先試試單個簡單的小檔案傳輸,首先先說說原理,這次我們先對檔案進行檔名獲取,將檔名以資訊傳輸的形式的先傳遞給服務端,目的是讓伺服器知道我們要傳送的檔名及檔案型別,接著再來發送檔案,這裡我們需要將檔案轉化成位元組

Android藍芽socket實現視訊實時傳輸,以及圖片和文字傳輸

目標 兩臺手機裝置之間能夠正常進行藍芽配對(藍芽模組兒和硬體掛鉤,所以需要兩臺真機) socket實現藍芽文字傳輸 實現圖片傳輸 實現實時視訊傳輸 程式碼下載:https://download.csdn.net/download/m0_37781149/10434336

Jquery+Django 實現 CORS 檔案傳輸

場景描述 前端處理過程 後端處理過程 場景描述 遇到這樣一個開發場景,伺服器A作為一個web server(可以看做master)而伺服器B 作為

如何實現高速檔案傳輸?用一個比喻向你說清楚

日常工作中,我們經常要給外地分/總公司的同事、眾多合作伙伴傳輸檔案。檔案稍微大一點經常傳輸速度很慢,如果要的不急還能忍受,如果在限定時間內很快傳給對方,這種龜速傳輸會讓人崩潰。 怎麼解決這個問題呢? 高速檔案傳輸可以簡單具象成三個方面:修一條高速路、修一條不堵車的高速路、買輛重卡拉貨

網路程式設計實驗三——TCP實現跨平臺檔案傳輸

一、實驗目的 1.在循環面向連線的程式基礎上,利用tcp完成linux和windows平臺的檔案傳輸。  2.對伺服器程式進行合理的封裝優化實驗步驟。 二、實驗分析 Linux伺服器: 1.首先,建立套接字,並將其繫結到提供服務的埠上,設定為被動模式,將這幾步進

QT實現TCP檔案傳輸

傳輸過程中TCP的使用見上一個帖子,介紹一下檔案傳輸 //主要用到了以下標頭檔案 #include <QFileDialog> //該函式返回對話方塊下選擇檔案目錄 QString filePath=QFileDialog::getOpenFileName(this,"open","

網路程式設計——3.TCP/UDP實現跨平臺檔案傳輸

一、實驗目的     在上次檔案傳輸的程式基礎上,利用循環面向連線、迴圈無連線方式完成linux和windows平臺的檔案傳輸,並完成客戶端、伺服器端程式碼的封裝。 二、實驗分析      1.使用TCP實現   在上次實驗基礎上,使用tcp_server.c的程式碼

java使用Apache工具集實現ftp檔案傳輸

本文主要介紹如何使用Apache工具集commons-net提供的ftp工具實現向ftp伺服器上傳和下載檔案。 一、準備 需要引用commons-net-3.5.jar包。 使用ma

嵌入式開發板iTOP-4412實現TFTP檔案傳輸

平臺:iTOP-4412開發板 本文講解如何通過 TFTP 來實現線上除錯應用程式。 TFTP(Trivial File Transfer Protocol,簡單檔案傳輸協議) ,是一個基於 UDP 協議實現的用於在客戶機和伺服器之間進行簡單檔案傳輸的協議,適合於開銷不大、

Socket程式設計------TCP檔案傳輸(文件、聲音、圖片、視訊和壓縮包等)

本程式是基於TCP穩定傳輸的檔案傳輸,可以相容任何型別任何格式的檔案傳輸。 ☆基本思路(客戶端) 客戶端需要明確伺服器的ip地址以及埠,這樣才可以去試著建立連線,如果連線失敗,會出現異常。 連線成功,說明客戶端與服務端建立了通道,那麼通過IO流就可以進行資料的傳輸,而So

Http協議格式——socket實現http檔案上傳

RT,做專案中有時候會遇到服務端為web服務,但在客戶端需要通過socket來與之互動的情況,這時候就需要用到socket來模擬http傳輸。。自己做過一次抓包分析,但是沒把結果記錄下來,後來做專案中需要用到,才百度了一下,現在把百度到的結果記錄下來…… 程式碼如下,具體結

Android Socket 實現批量圖片傳輸

        實現的原理其實也不難,苦於網上沒有現成的例子,所以就自己實現了一個。就是在socket 進行圖片資料傳輸的時候,自己去構建一個數據頭header ,然後另外一端在讀取資料的時候,以這個資料頭"start-xxxx"為依據實現image 影象的byte 資料讀

使用socket tcp實現簡單的檔案傳輸

程式分為server、client兩個部分,client從server獲取檔案。流程如下: server: 1、建立socket,繫結埠10002,等待client連線; 2、連結後開啟需要傳送的檔案,計算檔案長度併發送長度,等待接收客戶端響應; 3、客戶端響應ok後,傳送檔案資料,傳送

C#.網路程式設計 Socket基礎(三) 基於WinForm系統Socket TCP協議 實現端到端(伺服器與客戶端).txt.word.png等不同型別檔案傳輸

一、簡介: 前面的兩篇介紹了字串傳輸、圖片傳輸: 其實,本文針對Socket基礎(二)進一步完成,以便可以進行多種檔案傳輸。 二、基於不同的流(檔案流、記憶體流、網路等)讀寫。 1、圖片傳輸 方法一:(在客戶端用檔案流傳送(即將圖片寫到檔案流去,以便傳送),

windows環境下的socket程式設計(tcp檔案傳輸實現

開發環境 使用codeclock軟體進行程式設計 新建專案選擇console application完成相應的步驟即可。在專案下有main.c的檔案只需要將程式碼寫入其中即可。 程式碼設計 客戶端 client #include <std

Windows Socket程式設計之UDP實現檔案傳輸

前言:本文實現以下功能:在客戶端,使用者選擇本地的某個檔案,併發送到伺服器端。在伺服器端,接收客戶端傳輸的資料流,並按IP 地址儲存在伺服器端(文件名重複的,可以覆蓋)。如果傳輸過程中伺服器端發現客戶端斷開,伺服器端應刪除檔案,並在螢幕上提示,如“IP:1.2.3.4 發來a

Windows Socket程式設計之TCP實現檔案傳輸

前言: 本文實現以下功能: 在客戶端,使用者選擇本地的某個檔案,併發送到伺服器端。 在伺服器端,接收客戶端傳輸的資料流,並按IP 地址儲存在伺服器端(文 件名重複的,可以覆蓋)。 如果傳輸過程中伺服器端發現客戶端斷開,伺服器端應刪除檔案,並在螢幕 上提示,如“IP:1.