2011-01-11 68 views
1

我有一個客戶端/服務器應用程序。它們在接收數據時都使用異步調用。它與TCP構建,主要是爲了發送文件。異步網絡流到文件流(反之亦然)

一個命令是沿着一個套接字發送的,然後通過一個簡單的開關盒「轉換」成一個套接字。如果客戶端發送命令「SENDFILE」,我希望服務器能夠輸入一個調用函數的案例,然後該函數處理沿該套接字的任何進一步數據並將其合併到一個文件中。

這OnDataReceive回調函數和開關的情況下在服務器端:

public void OnDataReceived(IAsyncResult asyn) 
     { 
      SocketData socketData = (SocketData)asyn.AsyncState; 
      try 
      { 

       // Complete the BeginReceive() asynchronous call by EndReceive() method 
       // which will return the number of characters written to the stream 
       // by the client 
       socketData.m_currentSocket.EndReceive(asyn); 

       //Get packet dtata 
       Packet returnPacket = Helper.ByteArrayToPacket(socketData.dataBuffer); 

       switch (returnPacket.command) 
       { 
        case Command.SENDREQUEST: //Get ready for an incoming file  

這裏,從網絡數據流和異步讀取寫入到文件流同步類: 是嗎?

public static void NetToFile(NetworkStream net, FileStream file) 
     { 
      var copier = new AsyncStreamCopier(net, file); 
      copier.Start(); 
     } 

public class AsyncStreamCopier 
    { 
     public event EventHandler Completed; 

     private readonly Stream input; 
     private readonly Stream output; 

     private byte[] buffer = new byte[Settings.BufferSize]; 

     public AsyncStreamCopier(Stream input, Stream output) 
     { 
      this.input = input; 
      this.output = output; 
     } 

     public void Start() 
     { 
      GetNextChunk(); 
     } 

     private void GetNextChunk() 
     { 
      input.BeginRead(buffer, 0, buffer.Length, InputReadComplete, null); 
     } 

     private void InputReadComplete(IAsyncResult ar) 
     { 
      // input read asynchronously completed 
      int bytesRead = input.EndRead(ar); 

      if (bytesRead == 0) 
      { 
       RaiseCompleted(); 
       return; 
      } 

      // write synchronously 
      output.Write(buffer, 0, bytesRead); 

      // get next 
      GetNextChunk(); 
     } 

     private void RaiseCompleted() 
     { 
      if (Completed != null) 
      { 
       Completed(this, EventArgs.Empty); 
      } 
     } 
    } 

問題IM具有做相對,從文件流讀取到的NetworkStream,我應該從FILESTREAM異步讀取和寫入同步到網絡流?

也因爲與上述例子中,第一次啓動()被調用,函數結束它返回到服務器交換機情況下和任何另外的(文件)數據隨後被擊中Packet returnPacket = Helper.ByteArrayToPacket(socketData.dataBuffer);

和示數: (

* EDIT 1 *

  • 我不能使用任何外部庫或大量的代碼,這必須從地面向上建立。

  • 這不是典型的客戶機 - 服務器應用程序,它更多的P2P但不完全,每個應用程序都有自己的服務器和客戶端在不同的線程運行,這允許多個應用到所有連接到對方建立一個...網絡。

  • 客戶端告訴它正在發送一個文件給它的服務器,它不從服務器請求一個文件

+0

你的框架限制是什麼?你使用的是2.0,3.5還是4.0? – 2011-01-12 00:05:13

+0

.net 3.5。不超過總代碼的10%可以是一個框架,(目前的應用程序大約是10萬行代碼atm)。但是使用預先構建的框架可能對標記不利。 – Metalstorm 2011-01-12 00:09:21

回答

0

好了,我不認爲有任何直接回答你的問題;不過,這裏有幾點看法:

如果客戶端發送命令「SENDFILE」我希望服務器能夠...

這是一種辦法;但是,您可能會看到將控制反轉一點。獲取返回大小/版本信息的獲取文件信息。然後有一個讀取文件,需要一個偏移量和長度。現在,客戶端可以通過文件「輪詢」它的方式,而不是像服務器發送數據一樣快地吸收數據。

這裏是異步讀取網絡流並同步寫入文件流的類:是嗎?

是的,一目瞭然,看起來是正確的。

問題我有做相反的,從文件流讀取到網絡流,我應該從文件流異步讀取並同步寫入網絡流?

同樣,我會用一個客戶端輪詢循環一次拉文件的分片。這可以在插座斷開連接時重新啓動。

也因爲與上面的例子中,在第一時間啓動()被調用,函數結束...

是啊,這是怎麼回事的問題,一般的插座。您將不得不跟蹤每個套接字的一些狀態信息,以便您知道如何處理收到的字節。我是否正在寫文件,是否在等待命令等等。坦率地說,如果我正在寫這個(我不會用套接字),我會將所有內容都打包成長度爲前綴google protobuffer,其中包含關於每個請求的詳細信息。這允許您將狀態管理卸載到客戶端,而不是在服務器上進行跟蹤。

有人能指出我在正確的方向?從我所能看到的網絡上看,並不多。

我認爲一般的原因,你沒有找到太多的搜索網絡是因爲大多數(90%左右)甚至不嘗試這個。用套接字做這件事很困難,乏味,而且極易出錯。我甚至不會開始使用原始套接字進行通信。選擇任何現有的客戶端/服務器運輸並與之一起使用。如果您需要示例,我的建議可能會傾向於WCF。

乾杯,祝你好運!

+0

我添加了一些編輯的帖子,請看看他們。 – Metalstorm 2011-01-11 23:59:04

0

我想我已經解決了其中的一部分通過等待事件等等功能並沒有結束,它允許的NetworkStream - > FILESTREAM來完成。

現在的問題是如此一個文件流 - >網絡流。 「我應該從文件流中異步讀取並同步寫入網絡流嗎?」