我需要一个事件驱动的、基于Windows平台的、使用C#开发的TCP客户端。
当读取缓存中至少有35个字节时,我需要调用一个处理程序来读取这35字节,并从该“数据包”中获取长度值,然后以阻塞方式读取该长度的第二部分数据。
我需要一个事件驱动的、基于Windows平台的、使用C#开发的TCP客户端。
当读取缓存中至少有35个字节时,我需要调用一个处理程序来读取这35字节,并从该“数据包”中获取长度值,然后以阻塞方式读取该长度的第二部分数据。
有一个相对较新的项目可以提供这个功能:https://github.com/clariuslabs/reactivesockets
从他们的页面上可以看到:
基于IObservable实现了一套非常易于使用的套接字API。它允许非常简单的协议实现,例如:
var client = new ReactiveClient("127.0.0.1", 1055);
// The parsing of messages is done in a simple Rx query over the receiver observable
// Note this protocol has a fixed header part containing the payload message length
// And the message payload itself. Bytes are consumed from the client.Receiver
// automatically so its behavior is intuitive.
IObservable<string> messages = from header in client.Receiver.Buffer(4)
let length = BitConverter.ToInt32(header.ToArray(), 0)
let body = client.Receiver.Take(length)
select Encoding.UTF8.GetString(body.ToEnumerable().ToArray());
// Finally, we subscribe on a background thread to process messages when they are available
messages.SubscribeOn(TaskPoolScheduler.Default).Subscribe(message => Console.WriteLine(message));
client.ConnectAsync().Wait();
我不认为BCL中有任何基于事件的Socket类可用,但如果你只是想要比裸的Socket
更高级一些的东西,也许你应该研究一下TcpClient
。它将为您处理底层流的缓冲,让您可以通过StreamReader
等方式访问它:
TcpClient client;
// ... construct, connect, etc ...
new StreamReader(client.GetStream());
StreamReader.ReadLine()
,但StreamReader.Read()
也可以很容易地满足您的需求。Socket.BeginReceive()
和Socket.BeginSend()
。StartToken
,然后分析包的长度。StartTokenWithLengthInfoDataPackageAnalyzer
。如果现有的分析器不足,您也可以实现自己的分析器。
var dataPackageAnalyzer = new StartTokenWithLengthInfoDataPackageAnalyzer(0x01);
var dataPackageHandler = new DataPackageHandler(dataPackageAnalyzer);
dataPackageHandler.NewDataPackage += NewDataPackage;
void NewDataPackage(DataPackage dataPackage)
{
//final package
}
void OnDataReceived(byte[] receivedData)
{
//fragmented data
dataPackageHandler.AddData(receivedData);
}
using var cancellationTokenSource = new CancellationTokenSource(1000);
using var tcpClient = new TcpClient();
tcpClient.DataReceived += OnDataReceived;
await tcpClient.ConnectAsync("127.0.0.1", 9000, cancellationTokenSource.Token);
//Wait for data
Console.ReadKey();
tcpClient.Disconnect();
tcpClient.DataReceived -= OnDataReceived;
dataPackageHandler.NewDataPackage -= NewDataPackage;