所以我开始用套接字捣乱并异步读取它们。
第一个问题是它之间有什么区别:
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);
和
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, ReadCallback, readResult);
另外,考虑到这是我的回调函数,为什么我读到的示例在整个事情中有一个try / catch,当然你只需要围绕socket.EndReceive()
调用尝试/捕获?
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();
}
}
最后,如果您希望在致电socket.BeginReceive()
后优雅地关闭监听器,您会调用哪些功能以及如何管理它?
答案 0 :(得分:2)
a)他们是平等的。编译器将为您生成相同的代码
b)如何为异步调用编写一些扩展方法并处理异常,就好像它们是同步调用而不阻塞调用者一样?
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);
}
}
答案 1 :(得分:1)
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, new AsyncCallback(ReadCallback), readResult);
和
socket.BeginReceive(readResult.Buffer, 0, SocketReadResult.BufferSize, 0, ReadCallback, readResult);
两者都是一样的,与
相同 //both are the same thing
button1.Click += new EventHandler(button1_Click);
button1.Click += button1_Click;
答案 2 :(得分:0)
两次通话之间的差异可以忽略不计,你可以认为它们是等价的。第二个调用将帮助编译器为您输入类型推理,但在IntelliSense和代码自动完成之外,这将不会非常明显。我个人使用第一种格式,因为它更简洁。
至于为什么try/catch
不仅仅是Socket.EndReceive()
调用,主要与其他局部变量的范围有关。
考虑一下:
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.
}
正如你在这里看到的,有一些原因可以解释为什么一个较大的try/catch
优于两个较小的较小的try
。
首先,局部变量仅在try/catch
范围内可用。你可以通过在Socket.BeginReceive()
块之外定义它来解决这个问题。
其次,可能更重要的是,与减少冗余有关。由于您很可能在回调中再次呼叫try/catch
,因此将其置于同一SocketException
下是有意义的。否则,您必须在两个地方而不是一个地方处理您的潜在Socket
。
至于优雅地关闭Socket.Close()
,您可以使用false
方法。通常,套接字永远不会被重用,因此您可以为此传递Socket.Dispose()
。但是,最好在Socket.Close()
电话后拨打IDisposable
。如果您将侦听器套接字作为类的成员变量,请确保实现{{1}}接口并正确处理套接字。