基于TCP的大文件传输c语言项目
文章目錄
- 前言:功能實(shí)現(xiàn)
- tcp文件傳輸?shù)幕具^(guò)程:
- 1.用戶登錄
- 1.1創(chuàng)建數(shù)據(jù)庫(kù)
 
 
- 2.文件普通下載和上傳的實(shí)現(xiàn):
- 2.1 普通下載
- 2.2 普通上傳
- 2.3 文件秒上傳的實(shí)現(xiàn)
 
 
- 2.斷點(diǎn)下載和斷點(diǎn)上傳的實(shí)現(xiàn):
- 2.1 斷點(diǎn)下載
- 2.2 斷點(diǎn)上傳
- 2.3大文件傳輸
 
 
- 3.sendfile 零拷貝
- 4 演示圖:
- 4.1 啟動(dòng)服務(wù)端:
- 4.2 啟動(dòng)客戶端并注冊(cè)新用戶
- 4.3 上傳小文件:
- 4.4 上傳大文件并斷點(diǎn)續(xù)傳:
- 4.5 秒傳的實(shí)現(xiàn):
- 4.6 不同用戶上傳同一文件,其中某一個(gè)用戶中途退出
 
 
- 5 待完善的地方
- 5.1 一點(diǎn)小bug
- 5.2 自己運(yùn)行源碼時(shí)有問(wèn)題的地方
 
 
 
前言:功能實(shí)現(xiàn)
1.用戶登錄
 2.文件上傳,下載(包含大文件)
 3.斷點(diǎn)續(xù)傳,秒傳
 4.零拷貝
tcp文件傳輸?shù)幕具^(guò)程:
在傳輸文件數(shù)據(jù)之前,發(fā)送端會(huì)把文件名稱和文件長(zhǎng)度等信息的數(shù)據(jù)包發(fā)送至接收端,接收端收到文件名稱和文件長(zhǎng)度信息后會(huì)創(chuàng)建好空白文件。接著開(kāi)始傳輸文件數(shù)據(jù)。
服務(wù)端有一個(gè)創(chuàng)建新線程的函數(shù),一旦服務(wù)端監(jiān)聽(tīng)有連接請(qǐng)求,就創(chuàng)建新線程去連接該請(qǐng)求,即每個(gè)客戶端都是一個(gè)線程在服務(wù)器中運(yùn)行,互不干擾,基本滿足局域網(wǎng)內(nèi)的高并發(fā)訪問(wèn)。
1.用戶登錄
1.1創(chuàng)建數(shù)據(jù)庫(kù)
采用mysql,新建三個(gè)數(shù)據(jù)庫(kù)
其中,**user **表如下:
創(chuàng)建代碼如下:
因?yàn)槲覀兛紤]到斷點(diǎn)續(xù)傳和秒傳,需要用md5值記錄該文件在服務(wù)端是否存在。
輸入任意長(zhǎng)度的信息,經(jīng)過(guò)處理,輸出為128位的信息(數(shù)字指紋);
 不同的輸入得到的不同的結(jié)果(唯一性),采用是的散列函數(shù),hash算法。
 程序中計(jì)算md5值的方法,是利用LINUX支持OPENSSL并提供如下MD5函數(shù)。
 MD5_Init初始化MD5_CTX結(jié)構(gòu)。
 MD5_Update計(jì)算摘要。
 MD5_Final輸出摘要值。
其中,md5table表如下:
 
 創(chuàng)建代碼如下:
其中,serverStartInfo表如下:
創(chuàng)建代碼如下:
如果出現(xiàn)啟動(dòng)數(shù)據(jù)庫(kù)無(wú)法訪問(wèn),可能是要開(kāi)啟權(quán)限,具體參照下文。
 啟動(dòng)Mysql數(shù)據(jù)庫(kù)報(bào)錯(cuò)誤:-bash: ./start.sh: Permission denied
利用Shell編程實(shí)現(xiàn)多個(gè)接口用于用戶注冊(cè),登錄,插入文件信息到數(shù)據(jù)庫(kù),刪除某個(gè)文件記錄,md5值匹配后秒傳,判斷文件所屬是否是當(dāng)前用戶等等。同時(shí),系統(tǒng)也應(yīng)該有一個(gè)root用戶,擁有最高權(quán)限,可用來(lái)刪除文件,關(guān)閉服務(wù)器等操作。設(shè)置root用戶的方法也很簡(jiǎn)單,只需根據(jù)用戶名是否為root來(lái)設(shè)置一個(gè)標(biāo)志位即可,用于標(biāo)記該用于是否擁有管理員權(quán)限。
2.文件普通下載和上傳的實(shí)現(xiàn):
(注:下載是指客戶端從服務(wù)器下載文件,上傳是指客戶端上傳文件到服務(wù)器)
 考慮到下載或者上傳過(guò)程中有時(shí)會(huì)出現(xiàn)中斷,之后還要繼續(xù)下載,我們需要設(shè)置一個(gè)文件完整標(biāo)志位來(lái)表明操作完成的文件是否是完整的。
2.1 普通下載
普通下載在這里指的是一次性完成文件下載工作,無(wú)中斷。分析后可知,對(duì)于普通下載,我們需要在服務(wù)器端判斷待下載的文件是否完整—即進(jìn)入數(shù)據(jù)庫(kù)中查詢文件完整標(biāo)志位,完整的話就開(kāi)始下載。
2.2 普通上傳
??普通上傳在這里指的是一次性完成文件上傳工作,無(wú)中斷。由于考慮到多個(gè)用戶同時(shí)連接服務(wù)器的問(wèn)題,服務(wù)器端的數(shù)據(jù)庫(kù)是要存儲(chǔ)文件名,文件所屬(用戶),文件完整標(biāo)志位,以及md5值。這里md5值相當(dāng)于每個(gè)文件的數(shù)字指紋,用來(lái)標(biāo)識(shí)文件是否已經(jīng)存在于服務(wù)器端,用于判斷還需不需要繼續(xù)上傳該文件(即秒傳功能的實(shí)現(xiàn)),后面會(huì)詳細(xì)提到。
注:Message-Digest Algorithm 5(信息-摘要算法5)
??接下來(lái),普通上傳的實(shí)現(xiàn)就很簡(jiǎn)單,當(dāng)上傳文件成功后,文件完整標(biāo)志位置1,使得用戶可以下載該文件。
2.3 文件秒上傳的實(shí)現(xiàn)
前面提過(guò)每個(gè)文件都會(huì)有一個(gè)md5值。在客戶端上傳文件的時(shí)候,會(huì)先計(jì)算該文件的md5值,并把文件信息和md5值發(fā)送給服務(wù)器,服務(wù)器會(huì)從數(shù)據(jù)庫(kù)中匹配該文件名和md5值以及文件是否完整。若服務(wù)器中存在滿足上述三個(gè)條件的文件,說(shuō)明服務(wù)器中已經(jīng)存在該文件,保留這一個(gè)即可。若不滿足,再上傳文件后根據(jù)文件完整標(biāo)志位判斷使用普通上傳亦或是斷點(diǎn)上傳。
2.斷點(diǎn)下載和斷點(diǎn)上傳的實(shí)現(xiàn):
??所謂斷點(diǎn)下載,類似于我們?cè)赼pp商城中下載應(yīng)用,下載期間因某事中斷該下載后,繼續(xù)下載可以接著原來(lái)的進(jìn)度進(jìn)行下載,可提升傳輸效率。斷點(diǎn)上傳同理
2.1 斷點(diǎn)下載
??斷點(diǎn)下載,類似于接力賽,2道的選手要接力1道選手完成后序的任務(wù)。在這里,我們需要在客戶端計(jì)算出文件已經(jīng)有多大了,然后把文件大小發(fā)給服務(wù)端,服務(wù)端再將文件指針偏移到收到的文件大小處后,開(kāi)始發(fā)送給客戶端,即完成斷點(diǎn)下載。
2.2 斷點(diǎn)上傳
??斷點(diǎn)上傳的話相比于下載稍微復(fù)雜一些。由于是多用戶訪問(wèn)服務(wù)器端,我們?cè)谏蟼魑募臅r(shí)候,需要區(qū)分文件所屬(即是哪個(gè)用戶上傳的)。例如,用戶1上傳文件a,傳到一半暫停后(這時(shí),服務(wù)器端的數(shù)據(jù)庫(kù)里已經(jīng)有了用戶1和文件a的相關(guān)信息),有某一個(gè)用戶也上傳文件a。這時(shí),服務(wù)器端需要判斷這“ 某一個(gè)用戶”是否為用戶1。若是的話,就可以進(jìn)行斷點(diǎn)上傳。若不是,則說(shuō)明是其他用戶在上傳該文件a,這時(shí)文件a是需要完整重傳的。
 ?? 同樣,斷點(diǎn)上傳完畢后文件完整標(biāo)志位置1,方便后面用戶下載。
最后來(lái)說(shuō)說(shuō)下載上傳的實(shí)現(xiàn)細(xì)節(jié)
對(duì)于客戶端的文件下載方法:
對(duì)于服務(wù)端響應(yīng)客戶端文件下載的方法:
- 判斷收到的文件名在服務(wù)端是否存在或是否能被打開(kāi)
- 服務(wù)器端開(kāi)辟多個(gè)線程,根據(jù)客戶端發(fā)送的ok或是over進(jìn)行文件傳輸,傳輸過(guò)程中用poll監(jiān)測(cè)異常斷開(kāi)事件。
//
對(duì)于客戶端的文件上傳方法:
對(duì)于服務(wù)端響應(yīng)客戶端文件上傳的方法:
2.3大文件傳輸
Linux下open函數(shù)只能打開(kāi)2G以內(nèi)的文件,若大于2G,open會(huì)執(zhí)行失敗。
綜合了一些網(wǎng)上相關(guān)文章,原因在于:
 32位Linux系統(tǒng)內(nèi)部處理文件檔案是采用的指標(biāo)定義為long,在32位系統(tǒng)上,long為4字節(jié)即32位,因此只能尋址2^(32-1)=2G的范圍。
 更具體的,使用open,lseek函數(shù)操作文件時(shí),lseek原型為
 long lseek(int handle, long offset, int fromwhere);
 lseek函數(shù)用于指定文件操作指針的偏移量,其中offset參數(shù)表示偏移量大小,可用來(lái)將文件指針偏移用于對(duì)文件進(jìn)行寫入等操作。
那么要實(shí)現(xiàn)超過(guò)2G文件的傳輸,可采用如下方法:
 open函數(shù)原型:
 int open(const char *pathname, int flags, mode_t mode);
 flags參數(shù)表示打開(kāi)文件時(shí)所采用的操作,必選項(xiàng)包括只讀,只寫,可讀可寫三種操作之一;
 另外用追加、截?cái)唷?chuàng)建等操作與三個(gè)必選項(xiàng)按位或。
 第三個(gè)參數(shù)表示文件訪問(wèn)的權(quán)限,只有在第二個(gè)參數(shù)為創(chuàng)建時(shí)才有效。
3.sendfile 零拷貝
在作者提供的源碼v9版本中,作者使用了sendfile技術(shù);而v12版本中,我沒(méi)看到sendfile的使用,而是采用多線程實(shí)現(xiàn)分布式,采用IO多路復(fù)用中的poll實(shí)現(xiàn)對(duì)異常斷開(kāi)事件的監(jiān)測(cè)。
所謂的零拷貝技術(shù),就是指在傳統(tǒng)的read/write中,會(huì)發(fā)生多次CPU拷貝操作。而采用零拷貝技術(shù)后,直接將磁盤里的數(shù)據(jù)讀取到操作系統(tǒng)的內(nèi)核緩沖區(qū),這樣子就減少了數(shù)據(jù)拷貝,和上下文切換的次數(shù)。
 具體參見(jiàn)文章:Linux IO復(fù)用技術(shù)與零拷貝。
4 演示圖:
4.1 啟動(dòng)服務(wù)端:
4.2 啟動(dòng)客戶端并注冊(cè)新用戶
 登錄成功:
 
4.3 上傳小文件:
客戶端
 
 服務(wù)端:
 
4.4 上傳大文件并斷點(diǎn)續(xù)傳:
客戶端上傳過(guò)程中強(qiáng)制中止:
 
 服務(wù)端顯示
 
客戶端重新登錄并繼續(xù)上傳該文件:(會(huì)先得到已經(jīng)上傳的文件大小)
 
 服務(wù)端顯示:
 
4.5 秒傳的實(shí)現(xiàn):
客戶端重新上傳300M.mp4文件:
 
 服務(wù)器端顯示,(因?yàn)橹耙焉蟼鬟^(guò)該文件)
 
4.6 不同用戶上傳同一文件,其中某一個(gè)用戶中途退出
刪除3_4G.mp4文件后,使用用戶1重新上傳3_4G.mp4,中途中止,
 
接著用戶2上傳3_4G.mp4,
 
 服務(wù)器顯示:
 
 由于屬于不同用戶,該文件必須重傳而不能續(xù)傳。
5 待完善的地方
5.1 一點(diǎn)小bug
通過(guò)rm-f命令在bash界面刪除文件,md5表中仍然保留了文件的md5值。這算是一個(gè)小bug。
5.2 自己運(yùn)行源碼時(shí)有問(wèn)題的地方
源代碼下載下來(lái)后,直接運(yùn)行會(huì)出現(xiàn)各種各樣的問(wèn)題。其中有一個(gè)關(guān)于mysql的問(wèn)題,提示
錯(cuò)誤如下: 2058: This handle is already connected. Use a separate handle for each connet該問(wèn)題是由于源代碼中出現(xiàn)多次下列語(yǔ)句,比如client/user.c文件中27行,已經(jīng)建立了一個(gè)mysql連接,后面if語(yǔ)句里面又來(lái)了一個(gè)判斷,所以會(huì)報(bào)錯(cuò),mysql的句柄重復(fù)使用。
 該問(wèn)題在源代碼中出現(xiàn)次數(shù)比較多,親測(cè)刪除后就可以運(yùn)行了。
 
 修改過(guò)后的代碼鏈接如下:
 https://download.csdn.net/download/qq_35027690/21736932
總結(jié)
以上是生活随笔為你收集整理的基于TCP的大文件传输c语言项目的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
 
                            
                        - 上一篇: C#源代码—姓名 请输入老师的编号、姓名
- 下一篇: 飞桨创意赛火热进行中,总有一款AI时代C
