2011-09-21 36 views
0

寫一個客戶機/服務器程序和以前使用的電話是這樣的:試圖使代碼異步,但沒有阻止我的程序跑掉了?

TcpListener.AcceptTcpClient()NetworkStream.Read()NetworkStream.Write()

TcpListener.AcceptTcpClient()工作正常,因爲在建立連接後的回調函數只調用。

但是,BeginRead()也不能正常工作。出於某種原因,即使沒有數據發送,它也會執行並繼續通過。不知道發生了什麼。 NetworkStream.Read()擋住了就好了,但這不是..

這裏是每當建立連接時創建的非工作線程:

private void HandleClientCommunication(object client) 
{ 
    TcpClient tcpClient = (TcpClient)client; 
    NetworkStream clientStream = tcpClient.GetStream(); 

    try 
    { 
     byte[] header = new byte[4]; 

     clientStream.BeginRead(header, 0, header.Length, Read, new StateData(clientStream, header)); // Runs even if no data is sent 

     int dataLength = BitConverter.ToInt32(header, 0); // Continues to this, even if no packets are sent.. 

     byte[] data = new byte[dataLength]; // dataLength is 0 still of course because none of the code is blocking 

     clientStream.BeginRead(data, 0, dataLength, Read, new StateData(clientStream, data)); 
    } 
    catch (IOException e) 
    { 
     Console.WriteLine(e.InnerException.Message); 
    } 

    // not relevant past here 
} 

這裏的讀法了。不知道是否它是需要弄清楚的問題,但我會將它不分:

private void Read(IAsyncResult async) 
{ 
    StateData stateData = (StateData)async.AsyncState; 

    stateData.BytesRead += stateData.Stream.EndRead(async); 

    if (stateData.BytesRead < stateData.Bytes.Length) 
    { 
     stateData.Stream.BeginRead(stateData.Bytes, 0, stateData.Bytes.Length, Read, stateData); 
    } 
    else 
    { 
     string message = Encoding.ASCII.GetString(stateData.Bytes); 

     Console.WriteLine(message); 
    } 
} 

所以,是的,我只是試圖建立與異步調用的客戶機服務器交互,並有每一個「包」包括:頭部的數據長度爲int,然後是數據本身。不幸的是,事情似乎沒有奏效,我不確定問題是什麼。

好像我必須包括一些手動形式的阻止,但不會打敗使用異步調用的目的?那麼爲什麼不回到那個普通的同步阻止呼叫,如Read()AcceptTcpClient()那麼呢?

我不認爲我在這裏是完全理解的東西..

回答

3

然而,的BeginRead()不工作爲好。出於某種原因,即使沒有數據發送,它也會執行並繼續通過。不知道發生了什麼。 NetworkStream.Read()阻塞很好,但這不是..

我想你已經誤解了BeginRead是做什麼的。這不是意思是阻塞 - 它發出一個異步讀取,當讀取完成時執行給定的回調。這是意味着立即返回 - 所以它也不奇怪您的標題數據是空的。

基本上,任何需要數據的工作都應在回調中 - 而不是使用調用BeginRead的相同方法。你的第一個回調應該轉換標題數據,然後BeginRead再次用不同的回調來讀取消息數據本身......雖然你應該請記住,任何Read/BeginRead調用可能不會讀取所有你問過的數據對於。你試圖來解決你的回調中的這個問題,但你並不完全在那裏 - 因爲你總是試圖從開始填充緩衝區- 這將覆蓋任何現有的數據。如果您知道您期望的總體數據量和緩衝區的時間長度,則應該從開始讀入緩衝區,您已經讀取了多少個字節。

請注意,C#5將使所有這一切變得更加簡單 - 但如果您不能等到那時,您可能會發現返回阻止多線程(每個客戶端一個)的調用會更容易。

+0

感謝您的回覆。看起來好像即使沒有讀取任何內容,回調仍在執行。 BeginRead的回調在與*明顯*無數據連接時執行。不知道如何繼續.. –

+0

@加布裏埃爾:這可能是因爲你發出第二個BeginRead調用要求0字節的數據。這可能是即時執行的那個* call的回調。無論如何,你真的不應該再次調用'BeginRead'直到第一次讀取完成。 –

+0

你解釋得很好..我想我會去買你的書..大聲笑 –

相關問題