記乙個網路傳輸功能的實現過程

2022-03-11 09:43:16 字數 4743 閱讀 7362

寫在前面的話:功能是基於c/s模型的網路傳輸實現,要求是伺服器端可以在區域網中任何機子上執行,客戶端啟動後自動尋找伺服器端進行連線,之後,伺服器端向已經連線的客戶端傳送命令,客戶端根據命令執行相應的操作(即傳送某個約定資料夾下的所有檔案),並且客戶端不需要使用者操作。

第二,當伺服器端傳送命令給客戶端時,客戶端根據命令來決定傳送哪個資料夾中的檔案給伺服器端,由於資料夾下可能有多個檔案,所以需要有個迴圈,迴圈傳送每個檔案。我的處理時在傳送前先傳送即將傳送的檔案個數,之後迴圈傳送每個檔案,在每個檔案的傳送過程中,首先傳送檔名,之後傳送檔案長度,最後迴圈傳送檔案內容。當然伺服器端接受的時候也需要按這個順序來接收。

客戶端:

開啟乙個執行緒來傳送心跳包,每傳送乙個心跳包,就睡眠3s,接著傳送下乙個,如此迴圈,心跳包採用udp套接字來傳送。

當接受命令時,客戶端轉換為c/s模型中的伺服器端,因此客戶端需要開啟乙個執行緒來監聽固定埠,接受伺服器端傳送來的命令,之後根據命令執行相應的操作。

伺服器端:

開啟乙個執行緒監聽udp心跳包。根據心跳包的ip位址判斷是否做處理。

當點選傳送命令按鈕時,開啟乙個執行緒連線選中的客戶端,傳送命令並接收資料。

(1)客戶端的監聽是使用wsaasyncselect()函式註冊網路事件來實現的,註冊了fd_accept、fd_read、fd_close三個網路事件,**如下:

//

tcp套接字

if(inittcpsock())

listen(m_tcpsocket, 2);

}}

在fd_read網路事件發生時做處理,按接收到的命令執行相應的操作,出問題的地方就是當接受到傳送檔案的命令,執行相應的操作,傳送指定資料夾下所有檔案時,**如下:

1//

傳送指定資料夾所有檔案

2uint cclientdlg::sendfolderthread(lpvoid lpparameter)317

else18;

21 _itoa_s(ifilesum, szfilesum, 10

);22

if(socket_error == send(socket, szfilesum, 10

, null))

2330

\\*"

));32

cfilefind finder;

33 bool isfind =finder.findfile(strfolderpath);

34cstring strfilepath;

35cstring strfilename;

3637

while

(isfind)

3853

54char strbuf[512] = ;

55char strend[512] = ;

5657 uint len = 0;58

//傳送檔名

59 widechartomultibyte(cp_acp, 0

, 60 strfilename.getbuffer(strfilename.getlength() - 1

), 61 strfilename.getlength(), strbuf, 511, 0, 0

); 62

strfilename.releasebuffer();

63 strbuf[strfilename.getlength()] = 0;64

if(socket_error == send(socket, strbuf, 512

, null))

6570

//傳送檔案內容

71 memset(strbuf, 0, 512

);72

while(len = file.read(strbuf, 511

))73

80 memset(strbuf, 0, 512

);81

if(len < 511)82

86}87//

如果檔案長度剛好是511的整數倍

88if(0 ==len)

8992

file.close();93}

94}95//

afxmessagebox(_t("檔案傳送完畢"));96}

97delete psendparam;

98 psendparam =null;

99return

dwerror;

100 }

問題就出在這段**的74行,程式執行的時候總是提示10035錯誤**,根據錯誤**大全,這個錯誤是無法立即完成乙個非阻擋性套接字操作,原因就是說緩衝區已滿,無法立即完成傳送。在網上搜了一下,感覺這個帖子解釋的挺好的,摘抄幾個個人認為解釋的不錯的回覆:

10035錯誤的原因是無法立即完成乙個非阻擋性套接字操作。

原因就說緩衝區滿了 所以無法立即

tcp情況下:

負責監聽和接收的socket:可以採用非阻塞;

負責傳送的傳送的socket要採用阻塞模式;

因為tcp協議在網路上傳輸的兩端是阻塞傳輸的,你在**中設定非阻塞只是要socket把資料放到本地緩衝區上就不要管了,其實資料還在本地緩衝區,在上次發出去的資料沒有得到回應以前,資料將一直不會發出去,但這時你的socket又把下一批資料放入緩衝區,

在本機上,把傳送端的包大小設定為10240,接收的包設定為5120,會立即出錯。

解決辦法:

1.tcp情況下,把負責傳送的socket採用阻塞模式;

2.採用udp

10035出錯的原因是這樣的

因為你採用了wsaeventselect,這個函式會自動把socket設成了非阻塞模式。

非阻塞模式的socket在send前一定要檢查socket的當前狀態是否為可send狀態,因為你沒有合理的檢查機制,導至在socket不可send的狀態你send了。

阻塞模式的socket在send的時候不用檢查狀態的,可以直接send.

阻塞模式 寫法簡單,適合單連線。

用阻塞模式寫多連線也可以,不過有幾個連線,就得最少開幾個執行緒,為方便控制,書上推薦開連線數*2個執行緒。

非阻塞模式,相當難控制,對於現在的我來說,是個很大的工程,正在學習中...

如果有多個連線,書上建議用非阻塞模式,因為不管有多個連線,只要1-2個執行緒就可以搞定。

非阻塞模式有5種控制方法如下(抄書):

1.select模型

2.wsaasyncselect

3.wsaeventselect

4.重疊模型

5.完成埠模型

樓上說的其實都沒說到關鍵

樓主這樣傳送大檔案的方法根本不是正確的方法,因為這樣根本沒有考慮傳送快取是否已經滿了或網路的異常狀況,

這樣一直發一直發,完全不考慮結果,只要有乙個send沒傳送成功,那麼本次檔案傳送就會失敗,在實際應用中根本不可取;

樓主的做發是一種理想的做法;

如果非要這樣迴圈讀\迴圈send的話,可以在每次迴圈的時候sleep(10)一下,這樣基本就沒有問題,但不推薦這樣做,這樣會

使程式效率極其低效;

要做好大檔案的傳送,要考慮以下幾個方面:

1, 傳送快取的選取

2, 檔案的讀取,可以考慮使用記憶體檔案,如果能夠一次性讀取的話,就不要讀那麼多次,總之就是要減少讀取的次數

*  由於tcp/ip協議能夠自己進行流量控制,所以即使你在傳送的時候一次將整個檔案一次傳送,也不會有問題

*  send的時候沒必要每次只傳送一點點資料,太影響效率了,乙個檔案要傳送很久才能傳完

樓上的,

可以在每次迴圈的時候sleep(10)一下,這樣基本就沒有問題

//sleep(1000)該出問題還是會出問題,但通常加上sleep(1),這樣為防止cpu 100%,而不是防出錯

我搞不明白,把檔案拆開(只要不拆成1bit),有什麼不妥 1040-10240之間都可以執行的很好

發整個檔案,乙個檔案4m的話,就是4m記憶體,機器只執行你乙個程式?

樓上的,你沒明白我的意思

姑且不論sleep(1)是為了防止cpu 100%,還是防出錯,這無關緊要,

乙個合理高效的伺服器是不會這樣傳送資料的;

大檔案100%是要拆的,毫無疑問

一般的小檔案,又能佔多少記憶體呢!為什麼不能一次讀完?

我想說的是,每次"盡量"多從檔案讀些資料進來,避免頻繁讀寫磁碟,象這樣的**是沒有任何問題的:

int ret = fread( bug, sizeof(char) , 65536, pfile);

int nsend = send(msock,(char *)bug, ret, 0);

完成埠不存在這個問題是因為作業系統內部對待傳送的資料進行了快取,也就是說如果tcp的傳送緩衝區已滿則,作業系統會將你要傳送的資料加入待傳送佇列當檢測到傳送快取區中有空閒的時候在進行傳送。這也就是為什麼在進行完成埠的傳送時資料往往需要從堆上分配而不是棧上分配的具體原因。所以單純從吞吐量的角度來看完成埠不一定比 select + 非阻塞套接字的方式更高。

我認為第三個說的不錯,非阻塞模式的socket在send前一定要檢查socket的當前狀態是否為可send狀態,因為自己是初學網路程式設計,對於select模型的使用還不太熟練,所以不會使用他說的用select來檢測套接字緩衝區是否已滿。最後不得以換成了開執行緒的方法來實現。其次第五個說使用sleep這種方法我試了,不行。還是會出現同樣的錯誤**。

用乙個類實現網路通訊功能

背景或原因 環境 windows系統 可執行c 程式 網路連線正常 具體功能 完成tcp ip 通訊。其中tcp服務端 tcp客戶端 udp方式可選,以類似流的方式及使用 來接收和傳送且傳輸量可選。使用示例 include nstream.h int main return 0 標頭檔案 nstre...

記乙個網路營銷方案

什麼是豬八戒營銷聯盟?歡迎您來到豬八戒懸賞中心營銷聯盟!每乙個註冊會員都將自動獲得乙個自己的宣傳鏈結 例如 別人通過你的宣傳鏈結進入豬八戒懸賞平台,都能為你帶來現金或者積分收益!收益規則是 通過你的宣傳鏈結註冊乙個會員,系統將自動為你增加積分10分。該積分可以用來更換自己的會員頭像,檢視一些需要積分...

乙個簡單功能的SQL 實現

1.假設有一張表示cj表 name subject result 張三 語文 80張三 數學 90張三 物理 85李四 語文 85李四 數學 92李四 物理 89要求查詢結果 姓名 語文 數學 物理 張三 80 90 85李四 85 92 89 建立cj表sql create table cj id...