C# 支持网络I/O的异步和同步操作

C# 支持网络I/O的异步和同步操作,c#,.net,delegates,C#,.net,Delegates,首先,我必须声明,我没有太多的C#背景,所以我可能遗漏了一些明显的东西 我仅限于.NET3.5(因此没有异步/等待) 我为NetworkStream制作了一个包装器,它将读取“正好N”个字节(与传统的“最多N”个字节不同),并且不会阻塞当前线程。我想以阻塞的方式执行相同的操作(即,阻塞直到接收到正好N个字节,然后将这些字节返回给调用者),但是,显然,不需要编写一个完全独立的实现,例如使用读取 internal class ReadBytesContext { public Action&

首先,我必须声明,我没有太多的C#背景,所以我可能遗漏了一些明显的东西

我仅限于.NET3.5(因此没有异步/等待)

我为NetworkStream制作了一个包装器,它将读取“正好N”个字节(与传统的“最多N”个字节不同),并且不会阻塞当前线程。我想以阻塞的方式执行相同的操作(即,阻塞直到接收到正好N个字节,然后将这些字节返回给调用者),但是,显然,不需要编写一个完全独立的实现,例如使用
读取

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,但一旦达到收益,线程就会神奇地放回线程池中,并且执行不会停止