2016-09-13 66 views
0

這是從Socket讀取數據的好方法嗎?異步/等待插座接收數據問題

public class StateObject : IDisposable 
{ 
    private const int _bufferSize = 1024; 
    public byte[] Buffer { get; } = new byte[_bufferSize]; 
    public int BufferSize { get; } = _bufferSize; 
    public MemoryStream MsStream { get; } 

    public EnhStateObject() 
    { 
     MsStream = new MemoryStream(); 
    } 

    public void Dispose() 
    { 
     MsStream.Dispose(); 
    } 
} 

public async static Task<int> ReceiveAsync(this Socket client, StateObject state) 
{ 
    var task = await await Task<int>.Factory.FromAsync(
    (cb, s) => client.BeginReceive(state.Buffer, 0, state.BufferSize, SocketFlags.None, cb, s), 
    client.EndReceive, null).ContinueWith(t => 
    { 
     state.MsStream.Write(state.Buffer, 0, t.Result); 
     return t; 
    }); 

    if (task == state.BufferSize) await client.ReceiveAsync(state); 

    return task; 
} 

我的意思是,通過遞歸調用將對象轉移到對象外並將其存儲在對象中。

還是有更好的方法來使用相同的FromAsync包裝?

+1

如果這可行,那麼它可能更適合Code Review而不是SO。儘管可能需要添加更多細節(例如'StateObject'的定義可能會有所幫助)。 「等待」看起來很可疑。 –

+0

我已更新帖子。關於'StateObject'沒什麼特別的。 'await await' [here](https://blogs.msdn.microsoft.com/pfxteam/2011/10/24/task-run-vs-task-factory-startnew/) –

+0

同意,它可以更容易:刪除一個'等待'任務 .Factory.FromAsync'並從'ContinueWith''t.Result'返回' –

回答

1

不,這不是從套接字讀取數據的好方法。你正在這裏重新發明輪子; use NetworkStream instead。我不知道爲什麼你需要使用低級Socket API,但是,你不知道。

相反,在NetworkStream換你01​​爲調用,就像這樣:

Socket socket = ....; 
Stream stream = new NetworkStream(socket); 

然後,你可以閱讀使用ReadAsync()數據正如你所期望(積分:無狀態對象通過周圍,你可如果你正在使用TCP與標準MemoryStream嘲笑流中測試)

var buffer = new byte[1024]; 
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length); 

,我推薦使用the TcpClient API,而不是直接與插座的工作。

+0

Thnxs,這對我的服務器端使用'.net4.6.1'非常有用。怎麼樣與'.net4'的客戶端?如何使APM不沉到'Sockets' API的水平? –

+0

在你的問題中提及你的需求是個好主意,其中包括你正在使用的.NET框架。 .NET 4沒有'ReadAsync',但它仍然有'NetworkStream'。不幸的是,在沒有使用舊的'BeginRead' /'EndRead'方法的情況下,似乎沒有在該版本中使用異步讀取的方式 –

+0

對於需求的抱歉,我將在以後討論它。 –