Reputation: 355
I want a event-driven, windows, c#, tcp client.
When there are at least 35 bytes in the read buffer, I want a handler to be called that will read those 35 bytes, grab a length value from that "packet", then do a blocking read for that second length of data.
Upvotes: 7
Views: 24587
Reputation: 1079
The answer is probably too late. I recently had a similar problem and have developed 2 projects for it. The first one provides an event based TcpClient that has been tested for all major operating systems. It delivers all incoming data as an event that can be easily subscribed to. The 2nd project takes care of the processing of the incoming data. There is an analyzer that waits for a StartToken
and then analyzes the length of the package. StartTokenWithLengthInfoDataPackageAnalyzer
. You can also implement your own analyzer if the existing one is not sufficient.
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;
Upvotes: 1
Reputation: 25261
There's a relatively new project that essentially provides this: https://github.com/clariuslabs/reactivesockets
From their page:
Implements a very easy to use sockets API based on IObservable. It allows very simple protocol implementations such as:
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();
Upvotes: 4
Reputation: 4852
I don't believe there is any event-based socket class available in the BCL, but if you're just looking for something a bit higher level than a bare Socket
, perhaps you should look into TcpClient
. It will handle buffering the underlying stream for you, letting you access it through a StreamReader
and the like:
TcpClient client;
// ... construct, connect, etc ...
new StreamReader(client.GetStream());
If you were using a line based protocol, you'd only need to use StreamReader.ReadLine()
, but StreamReader.Read()
should easily suit your purposes as well.
Upvotes: 2
Reputation: 2436
To get going in the right direction, check out Socket.BeginReceive()
and Socket.BeginSend()
.
Also, here is a handy series of examples from Microsoft for how to use the above functions. That helped me get started with those.
Unfortunately I cannot see an option to invoke the callback unless there are at least 35 bytes in the read buffer; it will get invoked whenever anything is received -- even if it's zero bytes. However, chances are that the counterparty will not be sending you messages byte by byte anyway.
Upvotes: 1