我是C#的新手,但已经完成了多年的TCP和套接字编程。 我想创建一个程序来执行异步I / O(仅接收) 多个服务器。数据是文本,并由换行符分隔(非常简单)。
我的问题是,如果我使用StreamReader,是否可以假设 在我的异步读回调函数中,我是否可以认为
我理解它的方式,我想在我的网站上做一个StreamReader ReadLine 异步读回调。但是BeginRead中的内容会知道我真的 想做面向行的数据?我显然不知道阅读的长度 那时候。
我希望这是有道理的,并提前感谢!
米奇
答案 0 :(得分:1)
从您的帖子中我认为您需要创建自己的类,并将 SYNCHRONOUS 套接字包装到其中。当整行可用时,您将以阻塞的方式Read()
套接字,缓冲数据,拆分行并将事件激发给类使用者。
答案 1 :(得分:1)
基于我对您的问题的理解:您打算像阻塞流一样使用StreamReader
,但您使用的是异步套接字...即使我的理解错误,仍请查看建议因为它们还涵盖了您真正打算使用StreamReader
进行异步读取的情况。
它将能够获得至少一整行数据,并且
是和否:只要底层缓冲区有一个新行,它就会读取完整的数据行,但是,这是一个异步事件,所以一旦StreamReader
用完数据(即它到达最后一个新行) )即使你得到另一个异步回调,它也将不再有任何东西可读。基本上,您将接收缓冲区绑定到SocketAsyncEventArgs
,当您收到回调时,您的缓冲区就会被填充。之后您使用缓冲区做什么(您可以将其输入StreamReader
以读取行输入)。
它不会以某种方式阻止。
它不会阻止,但它不会获取您正在寻找的所有数据,具体取决于您实现异步回调的方式。这让我想到了下一点......
我的下一点:我不知道这是一个连续的数据流,还是只是一些行分隔的“批量”数据,但是,你有几个选择:
StreamWriter
编写缓冲区并使用StreamReader
读取行,直到您无法再读取任何新行。StreamReader
,然后读取所有行。这假定您具有固定大小的传入数据,而不是连续的“输入”流。ManualResetEvent
或某些东西)。它有点挫败异步套接字的目的,但它仍然可以让你利用这些好处。它比纯粹的阻塞套接字好一点,因为阻塞完全由你控制。我认为你最好的选择是#1,但另外2个可能不是不可能的,这取决于你想要做什么。
旁注:我created an async HTTP client,所以请随意查看它并清除任何有用的内容。我认为这两个函数对你来说是最重要的:
开始接收:
private void BeginReceive()
{
if ( _clientState == EClientState.Receiving)
{
if (_asyncTask.BytesReceived != 0 && _asyncTask.TotalBytesReceived <= _maxPageSize)
{
SocketAsyncEventArgs e = new SocketAsyncEventArgs();
e.SetBuffer(_asyncTask.ReceiveBuffer, 0, _asyncTask.ReceiveBuffer.Length);
e.Completed += new EventHandler<SocketAsyncEventArgs>(ReceiveCallback);
e.UserToken = _asyncTask.Host;
bool comletedAsync = false;
try
{
comletedAsync = _socket.ReceiveAsync(e);
}
catch (SocketException se)
{
Console.WriteLine("Error receiving data from: " + _asyncTask.Host);
Console.WriteLine("SocketException: {0} Error Code: {1}", se.Message, se.NativeErrorCode);
ChangeState(EClientState.Failed);
}
if (!comletedAsync)
{
// The call completed synchronously so invoke the callback ourselves
ReceiveCallback(this, e);
}
}
else
{
//Console.WriteLine("Num bytes received: " + _asyncTask.TotalBytesReceived);
ChangeState(EClientState.ReceiveDone);
}
}
}
和ReceiveCallback:
private void ReceiveCallback(object sender, SocketAsyncEventArgs args)
{
lock (_sync) // re-entrant lock
{
// Fast fail: should not be receiving data if the client
// is not in a receiving state.
if (_clientState == EClientState.Receiving)
{
String host = (String)args.UserToken;
if (_asyncTask.Host == host && args.SocketError == SocketError.Success)
{
try
{
Encoding encoding = Encoding.ASCII;
_asyncTask.BytesReceived = args.BytesTransferred;
_asyncTask.TotalBytesReceived += _asyncTask.BytesReceived;
// ********************************************
// You will need to replace the following line:
_asyncTask.DocSource += encoding.GetString(_asyncTask.ReceiveBuffer, 0, _asyncTask.BytesReceived);
// Write the contents of the ReceiveBuffer to a Stream using a StreamWriter
// Use the StreamReader associated with the same Stream to read the next line(s)
// ********************************************
BeginReceive();
}
catch (SocketException e)
{
Console.WriteLine("Error receiving data from: " + host);
Console.WriteLine("SocketException: {0} Error Code: {1}", e.Message, e.NativeErrorCode);
ChangeState(EClientState.Failed);
}
}
else if (_asyncTask.Host != host)
{
Console.WriteLine("Warning: received a callback for {0}, but the client is currently working on {1}.",
host, _asyncTask.Host);
}
else
{
Console.WriteLine("Socket Error: {0} when receiving from {1}",
args.SocketError,
_asyncTask.Host);
ChangeState(EClientState.Failed);
}
}
}
}
答案 2 :(得分:0)
据我所知,您无法使用内置类完成此操作。
您可以在StreamReader
上使用NetworkStream
来读取整行,但您需要自己编写异步部分,因为StreamReader
不会公开异步接口。或者,您可以使用异步的NetworkStream.BeginRead
,但是您必须编写代码以使其识别基于行的输入。