C# 支持网络I/O的异步和同步操作
首先,我必须声明,我没有太多的C#背景,所以我可能遗漏了一些明显的东西 我仅限于.NET3.5(因此没有异步/等待) 我为NetworkStream制作了一个包装器,它将读取“正好N”个字节(与传统的“最多N”个字节不同),并且不会阻塞当前线程。我想以阻塞的方式执行相同的操作(即,阻塞直到接收到正好N个字节,然后将这些字节返回给调用者),但是,显然,不需要编写一个完全独立的实现,例如使用C# 支持网络I/O的异步和同步操作,c#,.net,delegates,C#,.net,Delegates,首先,我必须声明,我没有太多的C#背景,所以我可能遗漏了一些明显的东西 我仅限于.NET3.5(因此没有异步/等待) 我为NetworkStream制作了一个包装器,它将读取“正好N”个字节(与传统的“最多N”个字节不同),并且不会阻塞当前线程。我想以阻塞的方式执行相同的操作(即,阻塞直到接收到正好N个字节,然后将这些字节返回给调用者),但是,显然,不需要编写一个完全独立的实现,例如使用读取 internal class ReadBytesContext { public Action&
读取
internal class ReadBytesContext
{
public Action<byte[]> Callback { get; private set; }
public byte[] Buffer { get; private set; }
public int ReadSoFar { get; set; }
public ReadBytesContext(
Action<byte[]> callback,
byte[] buffer,
int readSoFar)
{
Callback = callback;
Buffer = buffer;
ReadSoFar = readSoFar;
}
}
// Network-related exception handling omitted for brevity.
public class Connection
{
private NetworkStream _stream;
public Connection(NetworkStream stream)
{
_stream = stream;
}
public void ReadBytes(int numBytes, Action<byte[]> callback)
{
var buffer = new byte[numBytes];
_stream.BeginRead(
buffer,
0,
numBytes,
new AsyncCallback(ReadBytesMaybeDone),
new ReadBytesContext(callback, buffer, 0));
}
private void ReadBytesMaybeDone(IAsyncResult ar)
{
int bytesRead = _stream.EndRead(ar);
var context = (ReadBytesContext)ar.AsyncState;
context.ReadSoFar += bytesRead;
if (context.ReadSoFar < context.Buffer.Length)
{
_stream.BeginRead(
context.Buffer,
context.ReadSoFar,
context.Buffer.Length - context.ReadSoFar,
new AsyncCallback(ReadBytesMaybeDone),
context);
}
else
{
context.Callback(context.Buffer);
}
}
}
内部类ReadBytesContext
{
公共操作回调{get;private set;}
公共字节[]缓冲区{get;private set;}
public int ReadSoFar{get;set;}
公共ReadBytesContext(
动作回调,
字节[]缓冲区,
int readSoFar)
{
回调=回调;
缓冲区=缓冲区;
ReadSoFar=ReadSoFar;
}
}
//为简洁起见,省略了与网络相关的异常处理。
公共类连接
{
专用网络流;
公共连接(网络流)
{
_溪流=溪流;
}
public void ReadBytes(int numBytes,操作回调)
{
var buffer=新字节[numBytes];
_开始(
缓冲器
0,
纳姆比特斯,
新的异步回调(ReadBytesMaybeDone),
新的ReadByteContext(回调,缓冲区,0));
}
私有无效ReadBytesMaybeDone(IAsyncResult ar)
{
int bytesRead=_stream.EndRead(ar);
var context=(ReadBytesContext)ar.AsyncState;
context.ReadSoFar+=字节读取;
if(context.ReadSoFar
在c#中,这通常是一种有效的联网方法吗
可能不相关的附带问题:我如何为在线程池上运行的回调设置一个catch-all处理程序(在线程池中运行传递给Begin*的委托,对不对),因此,它们中未捕获的异常不会使应用程序崩溃?不,这不是一个很好的方法,因为如果客户端过早关闭网络流,可能会出现异常 你看过杰夫·里克特的异步枚举器吗?我以前在.NET3.5中使用过它。在nugget中查找Wintellect Powerthreading库。基本上,在yield返回之前的第一个代码块执行sync,但是一旦达到yield,线程就会神奇地放回线程池中,直到异步操作完成,执行才会恢复。这真是老派的异步/等待
private IEnumerator<int> ReadBytesEnumerator(AsyncEnumerator<byte[]> ae, int numbytes)
{
byte [] buffer = new byte[numbytes];
int totalBytes = 0;
while(totalBytes < numbytes)
{
_stream.BeginRead(buffer , totalBytes , numbytes - totalBytes , ae.End(), null);
yield return 1;
totalBytes +=_stream.EndRead(ae.DequeueResult());
}
ae.Result = buffer;
}
public IAsyncResult BeginReadBytes(int numBytes, AsyncCallback callback, object state)
{
AsyncEnumerator<byte []> ae = new AsyncEnumerator<byte[]>();
return ae.BeginExecute(ReadBytesEnumerator(ae, numBytes), callback, state);
}
public byte [] EndReadBytes(IAsyncResult result)
{
return AsyncEnumerator<byte[]>.FromAsyncResult(result).EndExecute();
}
private IEnumerator ReadBytesEnumerator(异步枚举器ae,int numbytes)
{
字节[]缓冲区=新字节[numbytes];
int totalBytes=0;
while(totalBytes
现在,无论何时调用EndReadBytes,都要由调用代码来处理任何异常。要使此方法同步,您可以只调用EndReadBytes(BeginReadBytes(numBytes,null,null);或者甚至使用ReadBytes方法包装该部分。不,这不是一个好方法,因为如果客户端过早关闭网络流,可能会出现异常 你看过Jeff Richter的AsyncEnumerator吗?我以前在.net 3.5中使用过它。在nugget中查找Wintellect Powerthreading库。基本上,在收益返回之前的第一个代码块执行sync,但一旦达到收益,线程就会神奇地放回线程池,直到a才恢复执行同步操作完成。这是老式的异步/等待
private IEnumerator<int> ReadBytesEnumerator(AsyncEnumerator<byte[]> ae, int numbytes)
{
byte [] buffer = new byte[numbytes];
int totalBytes = 0;
while(totalBytes < numbytes)
{
_stream.BeginRead(buffer , totalBytes , numbytes - totalBytes , ae.End(), null);
yield return 1;
totalBytes +=_stream.EndRead(ae.DequeueResult());
}
ae.Result = buffer;
}
public IAsyncResult BeginReadBytes(int numBytes, AsyncCallback callback, object state)
{
AsyncEnumerator<byte []> ae = new AsyncEnumerator<byte[]>();
return ae.BeginExecute(ReadBytesEnumerator(ae, numBytes), callback, state);
}
public byte [] EndReadBytes(IAsyncResult result)
{
return AsyncEnumerator<byte[]>.FromAsyncResult(result).EndExecute();
}
private IEnumerator ReadBytesEnumerator(异步枚举器ae,int numbytes)
{
字节[]缓冲区=新字节[numbytes];
int totalBytes=0;
while(totalBytes
现在,只要调用EndReadBytes,调用代码就可以处理任何异常。要使此方法同步,只需调用EndReadBytes(BeginReadBytes,numBytes,null,null);甚至可以使用ReadBytes方法包装该部分。不,这不是一个好方法,因为如果客户端过早关闭网络流,则可能会出现异常 你看过Jeff Richter的AsyncEnumerator吗?我以前在.net 3.5中使用过它。在nugget中查找Wintellect Powerthreading库。基本上,在收益返回之前的第一个代码块执行sync,但一旦达到收益,线程就会神奇地放回线程池中,并且执行不会停止