2011-08-17 82 views
0

我很新的網絡編程和我有一個關於這個代碼的一些問題:發送消息和文件上的NetworkStream

if (client.Connected) 
      { 
       ChangeLabel("Mit dem Server verbunden..."); 


       NetworkStream stream = client.GetStream(); 
       FileStream fs = null; 
       try 
       { 
        fs = new FileStream("Mapeditor2.exe", FileMode.Create); 
       } 
       catch (Exception e) 
       { 
        MessageBox.Show(e.Message); 
        Environment.Exit(0); 
       } 

       byte[] bResponse = new byte[16]; 
       stream.Read(bResponse, 0, 16); 
       string sResponse = System.Text.Encoding.UTF8.GetString(bResponse); 
       int NoOfPackets = Convert.ToInt32(sResponse); 
       float progress = 0; 
       float progressPercent = 100.0f/(float)NoOfPackets; 

       byte[] buffer = new byte[128];      
       int bytesRead; 

       for (int i = 0; i < NoOfPackets; i++) 
       { 
        bytesRead = stream.Read(buffer, 0, 128); 
        fs.Write(buffer, 0, bytesRead); 
        progress += progressPercent; 
        ChangeProgress((int)progress); 
       } 
       fs.Close(); 
       stream.Close(); 
      } 

(客戶端是一個TcpClient的,到服務器的連接)

現在正如你所看到的,我試圖爲我的機器人制作升級版。 首先,我發送一個16字節的消息,其中包含隨後將發送的軟件包數量(Mapeditor.exe文件!),這是針對客戶端的進度條的...

是否有任何動態的方式來執行這個? (不是說「讀取一個16字節的數組」,並將動態文本和文件寫入到客戶端的流中,並自動地知道他何時必須讀取文本和何時讀取文件)

我希望是這樣,還是有其他寫作方式更新程序/修補程序?遊戲開發者如何做到這一點?

謝謝!

PS:有沒有什麼辦法可以確保客戶端收到所有的包裹,如果有些丟失了,只發送這些包裹並放在一起?

回答

2

如果您使用的是TCP,則該協議會負責排序,重新發送等操作。

關於動態發送/接收數據,您可以使用前綴協議,在該協議中,您首先發送一個表示要發送的消息長度的數字(例如int - 4個字節)。之後,你發送剩餘的消息。

接收方等待4個字節,然後將它們轉換爲一個整數並等待該字節數。這個過程重複一遍又一遍。

在你的情況下,先讀16個字節沒有意義,把它解析成一個字符串,然後把字符串解析成一個int。您的發件人可以立即將int轉換爲字節:

// lengthBytes.Length = 4 bytes, which is sizeof(int) 
byte[] lengthBytes = BitConverter.GetBytes(anInt); 

end然後發送它在電線上。

然後,在接收端,在你的代碼,你喜歡:

byte[] msgLengthBytes = new byte[sizeof(int)]; // or hardcode 4 here, I'm a generalization junkie 
stream.Read(msgLengthBytes, 0, msgLengthBytes.Length); 
int msgLength = BitConverter.GetInt32(msgLengthBytes, 0); 

的而不是另外,它假設每次從流中讀取一次讀取的字節如數你期待,你應該使用這樣的事情:

int transfered = 0; 
while (transfered < msgLength) 
{ 
    bytesRead = stream.Read(buffer, 0, buffer.Length); 
    fs.Write(buffer, 0, bytesRead); 

    transfered += bytesRead; 

    progress += (bytesRead/msgLength) * 100; 
    ChangeProgress(progress); // You can't use int here anymore, use Math to round or something, for your progress bar 
} 

而且,在我的代碼段有可能是最後一次接收操作,你會閱讀量,如:轉移+ bytesRead> msgLengh,如果你發送的數據,連續上流。你也必須照顧這一點。無論如何,如果我是你,並且因爲你需要某種進度通知器,我會使用具有異步BeginRead()的流。

我剛給你一個ideea,你可以根據你的意願微調它。

+0

所以我現在使用的方法(見代碼)正是我應該怎麼做的? 就像我之前提到的,我發送一個16字節的數組,其中包含下一個要發送的文件的包大小。所以這是完全正確的,我在做什麼? –

+0

@Kevin Suppan編輯 – Vladimir

+0

謝謝!這非常有幫助! 但是現在我遇到了另一個問題:我嘗試在Ubuntu的MonoDevelop上運行它(Linux服務器比P便宜很多),它運行得非常好。但從客戶端收到的文件錯過了... 7kB! (所以.exe文件不能被執行......)。 在開始時計算出的包裝大小與我在Windows PC上試用時的包裝大小完全相同,儘管=/ –