![C#網(wǎng)絡(luò)編程-4_第1頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/11/2cbea9ea-533f-4322-bd6f-d0f4f5b4f159/2cbea9ea-533f-4322-bd6f-d0f4f5b4f1591.gif)
![C#網(wǎng)絡(luò)編程-4_第2頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/11/2cbea9ea-533f-4322-bd6f-d0f4f5b4f159/2cbea9ea-533f-4322-bd6f-d0f4f5b4f1592.gif)
![C#網(wǎng)絡(luò)編程-4_第3頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/11/2cbea9ea-533f-4322-bd6f-d0f4f5b4f159/2cbea9ea-533f-4322-bd6f-d0f4f5b4f1593.gif)
![C#網(wǎng)絡(luò)編程-4_第4頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/11/2cbea9ea-533f-4322-bd6f-d0f4f5b4f159/2cbea9ea-533f-4322-bd6f-d0f4f5b4f1594.gif)
![C#網(wǎng)絡(luò)編程-4_第5頁](http://file2.renrendoc.com/fileroot_temp3/2021-5/11/2cbea9ea-533f-4322-bd6f-d0f4f5b4f159/2cbea9ea-533f-4322-bd6f-d0f4f5b4f1595.gif)
版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
1、C#網(wǎng)絡(luò)編程(訂立協(xié)議和發(fā)送文件)-Part.4文件傳輸前面兩篇文章所使用的范例都是傳輸字符串,有的時(shí)候我們可能會(huì)想在服務(wù)端和客戶 端之間傳遞文件。比如,考慮這樣一種情況,假如客戶端顯示了一個(gè)菜單,當(dāng)我們輸入S1、S2或S3 (S為Send縮寫)時(shí),分別向服務(wù)端發(fā)送文件ClientO1.jpg 、Client02.jpg 、Client03.jpg ;當(dāng)我們輸入 R1、R2或R3時(shí)(R為Receive縮寫),則分別從服務(wù)端接收文 件 Server01.jpg 、 Server02.jpg 、 Server03.jpg 。那么,我們該如何完成這件事呢?此時(shí) 可能有這樣兩種做法:?類似于FTP協(xié)議
2、,服務(wù)端開辟兩個(gè)端口,并持續(xù)對這兩個(gè)端口偵聽:一個(gè) 用于接收字符串,類似于 FTP的控制端口,它接收各種命令(接收或發(fā) 送文件);一個(gè)用于傳輸數(shù)據(jù),也就是發(fā)送和接收文件。?服務(wù)端只開辟一個(gè)端口,用于接收字符串,我們稱之為控制端口。當(dāng)接到請求之后,根據(jù)請求內(nèi)容在客戶端開辟一個(gè)端口專用于文件傳輸,并在 傳輸結(jié)束后關(guān)閉端口?,F(xiàn)在我們只關(guān)注于上面的數(shù)據(jù)端口,回憶一下在第二篇中我們所總結(jié)的,可以得出:當(dāng)我們使用上面的方法一時(shí), 服務(wù)端的數(shù)據(jù)端口可以為多個(gè)客戶端的多次請求服務(wù);當(dāng)我們使用方法二時(shí), 服務(wù)端只為一個(gè)客戶端的一次請求服務(wù), 但是因?yàn)槊看握埱蠖紩?huì)重新開辟端 口,所以實(shí)際上還是相當(dāng)于可以為多個(gè)客戶
3、端的多次請求服務(wù)。 同時(shí), 因?yàn)樗粸橐淮握埱?服務(wù),所以我們在數(shù)據(jù)端口上傳輸文件時(shí)無需采用異步傳輸方式。 但在控制端口我們?nèi)匀恍?要使用異步方式。從上面看出,第一種方式要好得多,但是我們將采用第二種方式。至于原因,你可以回顧一下 Part.1 (基本概念和操作) 中關(guān)于聊天程序模式的講述,因?yàn)榻酉聛硪黄恼挛?們將創(chuàng)建一個(gè)聊天程序, 而這個(gè)聊天程序采用第三種模式, 所以本文的練習(xí)實(shí)際是對下一篇 的一個(gè)鋪墊。1. 訂立協(xié)議1.1發(fā)送文件我們先看一下發(fā)送文件的情況,如果我們想將文件clie ntO1.jpg由客戶端發(fā)往客戶端,那么流程是什么:1. 客戶端開辟數(shù)據(jù)端口用于偵聽,并獲取端口號,假設(shè)為
4、8005。2. 假設(shè)客戶端輸入了S1,則發(fā)送下面的控制字符串到服務(wù)端:file=Clie nt01.jpg, mode=se nd, port=8005。3. 服務(wù)端收到以后,根據(jù)客戶端ip和端口號與該客戶端建立連接。4. 客戶端偵聽到服務(wù)端的連接,開始發(fā)送文件。5. 傳送完畢后客戶端、服務(wù)端分別關(guān)閉連接。此時(shí),我們訂立的發(fā)送文件協(xié)議為:file=Clie nt01.jpg, mode=se nd, port=8005但是,由于它是一個(gè)普通的字符串,在上一篇中,我們采用了正則表達(dá)式來獲取其中的有效值,但這顯然不是一種好辦法。因此,在本文及下一篇文章中,我們采用一種新的方式來編寫協(xié)議:XML對于
5、上面的語句,我們可以寫成這樣的XMLvprotocolxfile name=client01.jpg mode=send port=8005 /這樣我們在服務(wù)端就會(huì)好處理得多,接下來我們來看一下接收文件的流程及其協(xié)議。NOTE這里說發(fā)送、接收文件是站在客戶端的立場說的,當(dāng)客戶端發(fā)送文件 時(shí),對于服務(wù)器來收,則是接收文件。1.2接收文件接收文件與發(fā)送文件實(shí)際上完全類似,區(qū)別只是由客戶端向網(wǎng)絡(luò)流寫入數(shù)據(jù),還是由 服務(wù)端向網(wǎng)絡(luò)流寫入數(shù)據(jù)。2. 假設(shè)客戶端輸入了R1,則發(fā)送控制字符串: 服務(wù)端。3. 服務(wù)端收到以后,根據(jù)客戶端ip和端口號與該客戶端建立連接。4. 客戶端建立起與服務(wù)端的連接,服務(wù)端開始
6、網(wǎng)絡(luò)流中寫入數(shù)據(jù)。5. 傳送完畢后服務(wù)端、客戶端分別關(guān)閉連接。2. 協(xié)議處理類的實(shí)現(xiàn)和上面一章一樣,在開始編寫實(shí)際的服務(wù)端客戶端代碼之前,我們首先要編寫處理協(xié)議的類,它需要提供這樣兩個(gè)功能:1、方便地幫我們獲取完整的協(xié)議信息,因?yàn)榍懊嫖覀冋f過,服務(wù)端可能將客戶端的多次獨(dú)立請求拆分或合并。比如,客戶端連續(xù)發(fā)送了兩條控制信息到服務(wù)端,而服務(wù)端將它們合并了,那么則需要先拆開再分別處理。2、方便地獲取我們所想要的屬性信息,因?yàn)閰f(xié)議是XML格式,所以還需要一個(gè)類專門對 XML進(jìn)行處理,獲得 字符串的屬性值。2.1 ProtocalHa ndler輔助類我們先看下ProtocalHandler,它與上一篇
7、中的RequestHa ndler作用相同。需要注意的是必須將它聲明為實(shí)例的,而非靜態(tài)的,這是因?yàn)槊總€(gè)TcpClie nt都需要對應(yīng)一個(gè)ProtocalHandler,因?yàn)樗鼉?nèi)部維護(hù)的patialProtocal不能共享,在協(xié)議發(fā)送不完整的情況下,這個(gè)變量用于臨時(shí)保存被截?cái)嗟淖址?。public stri ng GetProtocol(stri ngin put) retur n GetProtocol( in put, n ull );/獲得協(xié)議Iprivate stri ng GetProtocol( stri ng in put, List outputList) j iif (outp
8、utList = null )ioutputList =new List ();if ( String .1 sNullOrEmpty(input)return outputList.ToArray();if (! String .IsNullOrEmpty(partialProtocal)in put = partialProtocal + in put;stri ngpatter n = (A.*?)/縮短in put的長度in put = in put.Substri ng(match.Le ngth);/遞歸調(diào)用GetProtocol( in put, outputList); els
9、e /如果不匹配,說明協(xié)議的長度不夠,/那么先緩存,然后等待下一次請求 partialProtocal = in put; return outputList.ToArray();因?yàn)楝F(xiàn)在它已經(jīng)不是本文的重點(diǎn)了,所以我就不演示對于它的測試了,本文所附帶的代碼中含有它的測試代碼(我在ProtocolHandler中添加了一個(gè)靜態(tài)類 Test()。2.2 FileRequestType 枚舉和 FileProtocol 結(jié)構(gòu)因?yàn)閄ML是以字符串的形式在進(jìn)行傳輸,為了方便使用,我們最好構(gòu)建一個(gè)強(qiáng)類型來對它們進(jìn)行操作,這樣會(huì)方便很多。我們首先可以定義 FileRequestMode枚舉,它代表是發(fā)送還
10、是接收文件:public enum FileRequestMode 接下來我們再定義一個(gè)FileProtocol 結(jié)構(gòu),用來為整個(gè)協(xié)議字符串提供強(qiáng)類型的訪問,注意這里覆蓋了基類的 ToString()方法,這樣在客戶端我們就不需要再手工去編寫XML只要在結(jié)構(gòu)值上調(diào)用 ToString()就OK了,會(huì)方便很多。2.3 ProtocolHelper 輔助類這個(gè)類專用于將XML格式的協(xié)議映射為我們上面定義的強(qiáng)類型對象,這里我沒有加入try/catch異常處理,因?yàn)閰f(xié)議對用戶來說是不可見的,而且客戶端應(yīng)該總是發(fā)送正確的協(xié)議,我覺得這樣可以讓代碼更加清晰:public class ProtocolHel
11、per privateXmlNode fileNode;privateXmlNode root;public ProtocolHelper(stri ng protocol) XmlDocument doc = new XmlDocument();doc.LoadXml(protocol);root = doc.Docume ntEleme nt;fileNode = root.SelectS in gleNode(file);/ 此時(shí)的protocal一定為單條完整 protocalprivate FileRequestMode GetFileMode() stri ngmode = fil
12、eNode.Attributesmode.Value;mode = mode.ToLower();if (mode = send)return FileRequestMode.Se nd;ielse1return FileRequestMode.Receive;/獲取單條協(xié)議包含的信息public FileProtocol GetProtocol() FileRequestMode mode = GetFileMode();string fileName =;int port = 0;fileName = fileNode.Attributes name.Value;port = Con ve
13、rt.ToI nt32(fileNode.Attributesport.Value);retur nnew FileProtocol(mode, port, fileName);IOK我們又耽誤了點(diǎn)時(shí)間,下面就讓我們進(jìn)入正題吧。3. 客戶端發(fā)送數(shù)據(jù)3.1服務(wù)端的實(shí)現(xiàn)我們還是將一個(gè)問題分成兩部分來處理,先是發(fā)送數(shù)據(jù),然后是接收數(shù)據(jù)。我們先看發(fā)送數(shù)據(jù)部分的服務(wù)端。如果你從第一篇文章看到了現(xiàn)在,那么我覺得更多的不是技術(shù)上的問題而是思路,所以我們不再將重點(diǎn)放到代碼上,這些應(yīng)該很容易就看懂了。/打印連接到的客戶端信息Con sole .WriteL in e(n Clie nt Conn ected !
14、 0 0 en dpo in t);return ;/獲取發(fā)送文件的流Networkstream streamToClient = localClient.GetStream();/隨機(jī)生成一個(gè)在當(dāng)前目錄下的文件名稱stri ng path =!En viro nmen t.Curre ntDirectory +/ +j:gen erateFileName(protocol.FileName);byte fileBuffer =new byte 1024;/ 每次收 1KBFileStream fs = new FileStream (path, FileMode.CreateNew,File
15、Access.Write);/從緩存buffer中讀入到文件流中int bytesRead;iint totalBytes = 0;do ibytesRead = streamToClie nt.Read(buffer, 0, BufferSize);fs.Write(buffer, 0, bytesRead);這里應(yīng)該沒有什么新知識,需要注意的地方有這么幾個(gè):?在OnReadComplete()回調(diào)方法中的foreach循環(huán),我們使用委托異步調(diào)用了 handleProtocol()方法,這是因?yàn)?handleProtocol即將執(zhí)行的是一個(gè)讀取或接收文件的操作,也就是一個(gè)相對耗時(shí)的操作。?在
16、handleProtocol()方法中,我們深切體會(huì)了定義ProtocolHelper 類和FileProtocol結(jié)構(gòu)的好處。如果沒有定義它們,這里將是不堪入目的處理XML以及類型轉(zhuǎn)換的代碼。?handleProtocol()方法中進(jìn)行了一個(gè)條件判斷,注意sendFile()方法我屏蔽掉了,這個(gè)還沒有實(shí)現(xiàn),但是我想你已經(jīng)猜到它將是后面要實(shí)現(xiàn)的內(nèi)容。? receiveFile()方法是實(shí)際接收客戶端發(fā)來文件的方法,這里沒有什么特別之處。需要注意的是文件存儲(chǔ)的路徑,它保存在了當(dāng)前程序執(zhí)行的目錄下,文件的名稱我使用 generateFileName()生成了一個(gè)與時(shí)間有關(guān)的隨機(jī)名稱。3.2客戶端的
17、實(shí)現(xiàn)我們現(xiàn)在先不著急實(shí)現(xiàn)客戶端S1、R1等用戶菜單,首先完成發(fā)送文件這一功能,實(shí)際上,就是為上一節(jié) Sen dMessage()加一個(gè)姐妹方法 Se ndFile()。class Clie nt static void Main( string args) ConsoleKey key;ServerClientclient =new ServerClient ();stri ng filePath = En vir onmen t.Curre ntDirectory +/ +Clie ntO1.jpg;if ( File .Exists(filePath)clie nt.Begi nSe nd
18、File(filePath);Con sole .WriteLi ne(nn 輸入 Q鍵退岀?!?;do key =Con sole .ReadKey( true ).Key; while (key != ConsoleKey.Q);public class ServerClie ntprivateco nst int BufferSize = 8192;private byte buffer;privateTcpClie ntclie nt;private NetworkStream streamToServer;public ServerClie nt() try client = new
19、 TcpClient ();clie nt.Co nn ect(localhost , 8500);/ 與服務(wù)器連接 catch ( Exception ex) Con sole .WriteL in e(ex.Message);returnbuffer = new byte BufferSize;/打印連接到的服務(wù)端信息Con sole .WriteLi ne(Server Conn ected! 0 - 1clie nt.Clie nt. LocalE ndPoi nt,clie nt.Clie nt.RemoteE ndPoi nt);streamToServer = clie nt.G
20、etStream();/發(fā)送消息到服務(wù)端/發(fā)送文件-同步方法public void SendFile( stringfilePath) IPAddress ip = IPAddress.Parse( );TcpListener listener =new TcpListener (ip, 0);liste ner.Start();/獲取本地偵聽的端口號IPE ndPo int en dPo int = liste ner.LocalE ndpo intas IPE ndPo int;int listeningPort = endPoint.Port;/獲取發(fā)送的協(xié)議字符串st
21、ri ngfileName = Path.GetFileName(filePath);FileProtocol protocol =new FileProtocol(FileRequestMode.Se nd, liste nin gPort, fileName);stri ngpro = protocol.ToStr in g();Sen dMessage(pro);/ 發(fā)送協(xié)議到服務(wù)端/中斷,等待遠(yuǎn)程連接IITcpClie nt localClie nt = liste ner.AcceptTcpClie nt();IICon sole .WriteLi ne(Start sending
22、file.);NetworkStream stream = localClient.GetStream();iiii匚I/創(chuàng)建文件流IiFileStream fs = new FileStream (filePath, FileMode.Open,FileAccess.Read);byte fileBuffer =new byte 1024;/ 每次傳 1KBint bytesRead;int totalBytes = 0;/創(chuàng)建獲取文件發(fā)送狀態(tài)的類SendStatus status = new SendStatus (filePath);/將文件流轉(zhuǎn)寫入網(wǎng)絡(luò)流 try do Thread .
23、Sleep(10);/為了更好的視覺效果,暫停10毫秒:-) bytesRead = fs.Read(fileBuffer, 0,fileBuffer.Le ngth);stream.Write(fileBuffer, 0, bytesRead);totalBytes +=bytesRead;/發(fā)送了的字節(jié)數(shù)status.Pri ntStatus(totalBytes);/ 打印發(fā)送狀態(tài) while (bytesRead 0);Con sole .WriteLi ne(Total 0 bytes sent. Do ne!totalBytes); catch Con sole .WriteLi
24、ne(Server has lost. );stream.Dispose();fs.Dispose();localClie nt.Close();liste ner.Stop();i接下來我們來看下這段代碼,有這么兩點(diǎn)需要注意一下:?在Main()方法中可以看到,圖片的位置為應(yīng)用程序所在的目錄,如果你跟 我一樣處于調(diào)試模式,那么就在解決方案的Bin目錄下的Debug目錄中放置三張圖片 ClientO1.jpg 、Client02.jpg 、Client03.jpg,用來發(fā)往服務(wù)端。?我在客戶端提供了兩個(gè)SendFile()方法,和一個(gè)BeginSendFile()方法,分別用于同步和異步傳輸,其中私有的SendFile()方法只是一個(gè)輔助方 法。實(shí)際上對于發(fā)送文件這樣的操作我們幾乎總是需要使用異步操作。?SendMessage()方法中給 str
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 二零二五年度辦公室翻新與餐飲店改造設(shè)計(jì)施工合同
- 二零二五年度城市公共安全報(bào)警系統(tǒng)電路升級改造合同
- 提取公積金借款合同
- 銷售抵押合同
- 電商零售平臺開發(fā)合同
- 個(gè)人理財(cái)指南
- 農(nóng)產(chǎn)品公共檢測與溯源體系建設(shè)作業(yè)指導(dǎo)書
- 質(zhì)量管理工具與方法應(yīng)用作業(yè)指導(dǎo)書
- 平面設(shè)計(jì)聘用合同
- 2025年廣西貨運(yùn)考試題目
- 護(hù)理管理組織體系架構(gòu)圖
- 漸變方格模板
- 環(huán)境因素匯總識別及評價(jià)表(保衛(wèi)部 )
- GB/T 33880-2017熱等靜壓鋁硅合金板材
- 消防安全風(fēng)險(xiǎn)辨識清單
- 2023年版勞動(dòng)實(shí)踐河北科學(xué)技術(shù)出版社一年級下冊全冊教案
- 方案報(bào)審表(樣表)
- 除銹、油漆檢驗(yàn)批質(zhì)量驗(yàn)收記錄樣表
- pp顧問的常見面試問題
- 法理學(xué)原理與案例完整版教學(xué)課件全套ppt教程
- 軟體家具、沙發(fā)質(zhì)量檢驗(yàn)及工藝
評論
0/150
提交評論