日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

基于TCP的大文件传输c语言项目

發布時間:2024/3/26 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 基于TCP的大文件传输c语言项目 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

    • 前言:功能實現
    • tcp文件傳輸的基本過程:
    • 1.用戶登錄
        • 1.1創建數據庫
    • 2.文件普通下載和上傳的實現:
        • 2.1 普通下載
        • 2.2 普通上傳
        • 2.3 文件秒上傳的實現
    • 2.斷點下載和斷點上傳的實現:
        • 2.1 斷點下載
        • 2.2 斷點上傳
        • 2.3大文件傳輸
    • 3.sendfile 零拷貝
    • 4 演示圖:
        • 4.1 啟動服務端:
        • 4.2 啟動客戶端并注冊新用戶
        • 4.3 上傳小文件:
        • 4.4 上傳大文件并斷點續傳:
        • 4.5 秒傳的實現:
        • 4.6 不同用戶上傳同一文件,其中某一個用戶中途退出
    • 5 待完善的地方
        • 5.1 一點小bug
        • 5.2 自己運行源碼時有問題的地方

前言:功能實現

1.用戶登錄
2.文件上傳,下載(包含大文件)
3.斷點續傳,秒傳
4.零拷貝

tcp文件傳輸的基本過程:

在傳輸文件數據之前,發送端會把文件名稱和文件長度等信息的數據包發送至接收端,接收端收到文件名稱和文件長度信息后會創建好空白文件。接著開始傳輸文件數據。

服務端有一個創建新線程的函數,一旦服務端監聽有連接請求,就創建新線程去連接該請求,即每個客戶端都是一個線程在服務器中運行,互不干擾,基本滿足局域網內的高并發訪問。

1.用戶登錄

1.1創建數據庫

采用mysql,新建三個數據庫

  • loginUser數據庫,表為user,用于保存用戶名和密碼,用于登錄匹配。
    其中,**user **表如下:

    創建代碼如下:
  • create table user(id int(11) primary key AUTO_INCREMENT ,name varchar(20),passwd varchar(20));
  • md5數據庫,表為md5table,用于存儲文件信息:(文件名,md5值,文件屬于哪個用戶,文件完整標志位)
    因為我們考慮到斷點續傳和秒傳,需要用md5值記錄該文件在服務端是否存在。
  • 輸入任意長度的信息,經過處理,輸出為128位的信息(數字指紋);
    不同的輸入得到的不同的結果(唯一性),采用是的散列函數,hash算法。
    程序中計算md5值的方法,是利用LINUX支持OPENSSL并提供如下MD5函數。
    MD5_Init初始化MD5_CTX結構。
    MD5_Update計算摘要。
    MD5_Final輸出摘要值。

    其中,md5table表如下:

    創建代碼如下:

    create table md5table(filename varchar(50) primary key ,md5Value varchar(50),username varchar(20),intact varchar(20));
  • serverLog數據庫,表為serverStartInfo,用于記錄服務器的啟動時間,啟動次數。
    其中,serverStartInfo表如下:

    創建代碼如下:
  • create table serverStartInfo(times int(11) primary key AUTO_INCREMENT ,date varchar(50));
  • 如果出現啟動數據庫無法訪問,可能是要開啟權限,具體參照下文。
    啟動Mysql數據庫報錯誤:-bash: ./start.sh: Permission denied

  • 利用Shell編程實現多個接口用于用戶注冊,登錄,插入文件信息到數據庫,刪除某個文件記錄,md5值匹配后秒傳,判斷文件所屬是否是當前用戶等等。同時,系統也應該有一個root用戶,擁有最高權限,可用來刪除文件,關閉服務器等操作。設置root用戶的方法也很簡單,只需根據用戶名是否為root來設置一個標志位即可,用于標記該用于是否擁有管理員權限。

  • 2.文件普通下載和上傳的實現:

    (注:下載是指客戶端從服務器下載文件,上傳是指客戶端上傳文件到服務器)
    考慮到下載或者上傳過程中有時會出現中斷,之后還要繼續下載,我們需要設置一個文件完整標志位來表明操作完成的文件是否是完整的。

    2.1 普通下載

    普通下載在這里指的是一次性完成文件下載工作,無中斷。分析后可知,對于普通下載,我們需要在服務器端判斷待下載的文件是否完整—即進入數據庫中查詢文件完整標志位,完整的話就開始下載。

    2.2 普通上傳

    ??普通上傳在這里指的是一次性完成文件上傳工作,無中斷。由于考慮到多個用戶同時連接服務器的問題,服務器端的數據庫是要存儲文件名文件所屬(用戶),文件完整標志位,以及md5值。這里md5值相當于每個文件的數字指紋,用來標識文件是否已經存在于服務器端,用于判斷還需不需要繼續上傳該文件(即秒傳功能的實現),后面會詳細提到。

    注:Message-Digest Algorithm 5(信息-摘要算法5)

    ??接下來,普通上傳的實現就很簡單,當上傳文件成功后,文件完整標志位置1,使得用戶可以下載該文件。

    2.3 文件秒上傳的實現

    前面提過每個文件都會有一個md5值。在客戶端上傳文件的時候,會先計算該文件的md5值,并把文件信息和md5值發送給服務器,服務器會從數據庫中匹配該文件名md5值以及文件是否完整。若服務器中存在滿足上述三個條件的文件,說明服務器中已經存在該文件,保留這一個即可。若不滿足,再上傳文件后根據文件完整標志位判斷使用普通上傳亦或是斷點上傳。

    2.斷點下載和斷點上傳的實現:

    ??所謂斷點下載,類似于我們在app商城中下載應用,下載期間因某事中斷該下載后,繼續下載可以接著原來的進度進行下載,可提升傳輸效率。斷點上傳同理

    2.1 斷點下載

    ??斷點下載,類似于接力賽,2道的選手要接力1道選手完成后序的任務。在這里,我們需要在客戶端計算出文件已經有多大了,然后把文件大小發給服務端,服務端再將文件指針偏移到收到的文件大小處后,開始發送給客戶端,即完成斷點下載。

    2.2 斷點上傳

    ??斷點上傳的話相比于下載稍微復雜一些。由于是多用戶訪問服務器端,我們在上傳文件的時候,需要區分文件所屬(即是哪個用戶上傳的)。例如,用戶1上傳文件a,傳到一半暫停后(這時,服務器端的數據庫里已經有了用戶1和文件a的相關信息),有某一個用戶也上傳文件a。這時,服務器端需要判斷這“ 某一個用戶”是否為用戶1。若是的話,就可以進行斷點上傳。若不是,則說明是其他用戶在上傳該文件a,這時文件a是需要完整重傳的。
    ?? 同樣,斷點上傳完畢后文件完整標志位置1,方便后面用戶下載。

    最后來說說下載上傳的實現細節

    對于客戶端的文件下載方法:

  • 判斷輸入的文件名是否存在。存在則進行下一步
  • 發送下載命令給服務器,收到服務器回復的消息(包括服務器端該文件是否存在,以及文件是否完整,不完整則不允許下載)
  • 判斷客戶端是否已存在該文件,若不存在,則需要新建該文件用于后面從服務端來的文件內容寫入該新建文件中。若存在,則需要判斷客戶端文件大小服務端文件大小,這二者之間的關系。若客>服,說明客戶端該文件已被人為修改過,需要重新從服務端下載(客戶端發送ok告訴服務器開啟傳輸,傳輸完成后發送over告訴其終止傳輸)。若客=服,說明不需要下載(客戶端發送over告訴服務器終止傳輸)。若客<服,說明文件內容不完整需要斷點下載(待傳輸完成后發送over告訴其終止傳輸)。
  • 對于服務端響應客戶端文件下載的方法:

    • 判斷收到的文件名在服務端是否存在或是否能被打開
    • 服務器端開辟多個線程,根據客戶端發送的ok或是over進行文件傳輸,傳輸過程中用poll監測異常斷開事件。

    //

    對于客戶端的文件上傳方法:

  • 判斷文件名是否存在(包括是否能打開文件和文件名是否存在)。存在則進行下一步
  • 發送上傳命令給服務器,同時開一個進程用以計算文件的md5值并發送給服務器。服務器根據md5值判斷是否已經存在該文件,若存在且完整(服務器返回exist表示存在且完整),客戶端告知服務器結束傳輸完成秒傳(向服務端發送over終止)。若不存在亦或是存在但不完整,客戶端發服務端發送begin告知服務端開始上傳文件,同時根據服務端對文件是否完整選擇是重傳還是斷點上傳。
  • 對于服務端響應客戶端文件上傳的方法:

  • 服務端接收到begin開始準備上傳文件
  • 先匹配md5值且判斷文件是否完整,來進行是否秒傳的選擇
  • 若md5不匹配或者文件不完整,服務器先接收客戶端已存在部分文件大小與服務端本地文件大小進行比較來選擇重傳或者斷點上傳(注:這里作者的邏輯我有些沒看懂,好像只實現了斷點重傳時對不同用戶的文件進行判斷的問題(不同用戶對斷點重傳是采用刪除重傳的方法,感覺有點bug)。
  • 2.3大文件傳輸

    Linux下open函數只能打開2G以內的文件,若大于2G,open會執行失敗。

    綜合了一些網上相關文章,原因在于:
    32位Linux系統內部處理文件檔案是采用的指標定義為long,在32位系統上,long為4字節即32位,因此只能尋址2^(32-1)=2G的范圍。
    更具體的,使用open,lseek函數操作文件時,lseek原型為
    long lseek(int handle, long offset, int fromwhere);
    lseek函數用于指定文件操作指針的偏移量,其中offset參數表示偏移量大小,可用來將文件指針偏移用于對文件進行寫入等操作。

    那么要實現超過2G文件的傳輸,可采用如下方法:
    open函數原型:
    int open(const char *pathname, int flags, mode_t mode);
    flags參數表示打開文件時所采用的操作,必選項包括只讀,只寫,可讀可寫三種操作之一;
    另外用追加、截斷、創建等操作與三個必選項按位或。
    第三個參數表示文件訪問的權限,只有在第二個參數為創建時才有效

  • 在open函數中,flags 使用O_LARGEFILE 表示打開大文件。(或者直接使用open64函數打開)
  • 改用lseek64, ftruncate64(),atoi() 函數要改為 atoll()等。
  • 獲取文件大小由int類型改為long long 類型,輸出文件大小用%lld。
  • 3.sendfile 零拷貝

    在作者提供的源碼v9版本中,作者使用了sendfile技術;而v12版本中,我沒看到sendfile的使用,而是采用多線程實現分布式,采用IO多路復用中的poll實現對異常斷開事件的監測。

    所謂的零拷貝技術,就是指在傳統的read/write中,會發生多次CPU拷貝操作。而采用零拷貝技術后,直接將磁盤里的數據讀取到操作系統的內核緩沖區,這樣子就減少了數據拷貝,和上下文切換的次數。
    具體參見文章:Linux IO復用技術與零拷貝。

    4 演示圖:

    4.1 啟動服務端:

    4.2 啟動客戶端并注冊新用戶


    登錄成功:

    4.3 上傳小文件:

    客戶端

    服務端:

    4.4 上傳大文件并斷點續傳:

    客戶端上傳過程中強制中止:

    服務端顯示

    客戶端重新登錄并繼續上傳該文件:(會先得到已經上傳的文件大小)

    服務端顯示:

    4.5 秒傳的實現:

    客戶端重新上傳300M.mp4文件:

    服務器端顯示,(因為之前已上傳過該文件)

    4.6 不同用戶上傳同一文件,其中某一個用戶中途退出

    刪除3_4G.mp4文件后,使用用戶1重新上傳3_4G.mp4,中途中止,

    接著用戶2上傳3_4G.mp4,

    服務器顯示:

    由于屬于不同用戶,該文件必須重傳而不能續傳。

    5 待完善的地方

    5.1 一點小bug

    通過rm-f命令在bash界面刪除文件,md5表中仍然保留了文件的md5值。這算是一個小bug。

    5.2 自己運行源碼時有問題的地方

    源代碼下載下來后,直接運行會出現各種各樣的問題。其中有一個關于mysql的問題,提示

    錯誤如下: 2058: This handle is already connected. Use a separate handle for each connet

    該問題是由于源代碼中出現多次下列語句,比如client/user.c文件中27行,已經建立了一個mysql連接,后面if語句里面又來了一個判斷,所以會報錯,mysql的句柄重復使用。
    該問題在源代碼中出現次數比較多,親測刪除后就可以運行了。

    修改過后的代碼鏈接如下:
    https://download.csdn.net/download/qq_35027690/21736932

    總結

    以上是生活随笔為你收集整理的基于TCP的大文件传输c语言项目的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。