Reputation: 19
Is this is a good approach to read data from 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;
}
I mean, transfer outside the object and storing the received information in it through the recursive call.
Or is there a more elegant way to do this using the same FromAsync
wrapper?
Upvotes: 1
Views: 2083
Reputation: 10548
No, this is not a good way of reading data from a socket. You are reinventing the wheel here; use NetworkStream
instead. I don't know why you need to use the low-level Socket
API, but, well, you don't.
Instead, wrap your Socket
in a NetworkStream
at the callsite, like so:
Socket socket = ....;
Stream stream = new NetworkStream(socket);
Then you can just read data using ReadAsync()
as you would expect (bonus points: no state object to pass around and you can mock the stream with a standard MemoryStream
in tests)
var buffer = new byte[1024];
var bytesRead = await stream.ReadAsync(buffer, 0, buffer.Length);
If you're using Tcp, I'd recommend using the TcpClient API instead of working directly with sockets.
Upvotes: 4