Reputation: 14379
So I've started to muck around with sockets and asynchronously reading from them.
First question is what is the difference between this:
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);
and
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, ReadCallback, readResult);
Also, given this as my callback function, why did the example I read have a try/catch around the whole thing, surely you only need a try/catch around the socket.EndReceive()
call?
public void ReadCallback(IAsyncResult ar)
{
try
{
var readResult = (SocketReadResult)ar.AsyncState;
var socket = readResult.Socket;
int bytesRead = socket.EndReceive(ar);
if (bytesRead > 0)
{
// There might be more data, so store the data received so far.
readResult.Text.Append(Encoding.ASCII.GetString(readResult.Buffer, 0, bytesRead));
// Get the rest of the data.
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);
}
else
{
var newRead = new SocketReadResult(socket);
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), newRead);
// All the data has arrived; put it in response.
if (readResult.Text.Length > 1) ((IMessageSender)this).RouteMessage(this, new MessageString(readResult.Text.ToString()));
}
}
catch (Exception e)
{
// TODO: manage this exception.
}
}
public struct SocketReadResult
{
StringBuilder Text;
Socket Socket;
byte[] Buffer;
public const int BufferSize = 1024;
public SocketReadResult(Socket s)
{
Socket = s;
Buffer = new byte[BufferSize];
Text = new StringBuilder();
}
}
Last of all, should you wish to gracefully close the listener after you have called socket.BeginReceive()
, what functions do you call and how is it managed?
Upvotes: 0
Views: 2514
Reputation: 35353
a) They are equal. Compiler will generate the same code for you
b) How about writing some extension methods for async calls and handle the exceptions as if they were sync calls without blocking the caller?
try
{
await socket.ConnectTaskAsync("www.google.com", 80);
await socket.SendTaskAsync(bytesToSend);
byte[] buf = new byte[0x8000];
var bytesRead = await socket.ReceiveTaskAsync(buf, 0, buf.Length);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
public static class SocketExtensions
{
public static Task ConnectTaskAsync(this Socket socket, string host, int port)
{
return Task.Factory.FromAsync(
socket.BeginConnect(host, port, null, null),
socket.EndConnect);
}
public static Task<int> ReceiveTaskAsync(this Socket socket,
byte[] buffer,
int offset,
int count)
{
return Task.Factory.FromAsync<int>(
socket.BeginReceive(buffer, offset, count, SocketFlags.None, null, socket),
socket.EndReceive);
}
public static Task SendTaskAsync(this Socket socket, byte[] buffer)
{
return Task.Factory.FromAsync<int>(
socket.BeginSend(buffer,0,buffer.Length,SocketFlags.None, null, socket),
socket.EndSend);
}
}
Upvotes: 2
Reputation: 12858
The difference between the two calls is negligible and you can consider them equivalent. The second call will help the compiler do type inferencing for you, but that won't be very noticeable outside IntelliSense and auto-completion of code. I personally use the first format since it is more concise.
As for why the try/catch
is more than just the Socket.EndReceive()
call mostly has to do with the scope of other local variables.
Consider this:
var state = result.AsyncState as SocketStateObject;
var socket = state.Socket;
try
{
var numberOfBytesRead = socket.EndReceive(result);
}
catch(SocketException ex)
{
// Handle the exception here.
}
// numberOfBytesRead is not accessible out here!
try
{
if(socket.Connected)
socket.BeginReceive(...); // Receive again!
}
catch(SocketException ex)
{
// Handle the exception here too.
}
As you can see here, there are a couple reasons why one, larger try/catch
is preferable to two separate, smaller ones.
First off, local variables are only available within the scope of the try
. You could solve that by defining it higher outside the try/catch
block.
Secondly, and probably more importantly, has to do with reducing redundancy. Since you are more than likely going to call Socket.BeginReceive()
again in your callback, it makes sense to put it under the same try/catch
. Otherwise, you'd have to handle your potential SocketException
in two places instead of just one.
As for closing a Socket
gracefully, you can use the Socket.Close()
method. Typically sockets are never reused so you can pass false
for that. However, it is preferable to call Socket.Dispose()
as well, after the Socket.Close()
call. If you are holding the listener socket as a member variable of your class, make sure you implement the IDisposable
interface and properly dispose of your socket.
Upvotes: 0
Reputation: 20575
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);
and
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, ReadCallback, readResult);
both are the same thing, its same thing as
//both are the same thing
button1.Click += new EventHandler(button1_Click);
button1.Click += button1_Click;
Upvotes: 1