Library, that provides Mailbox class. The Mailbox class is a shell for a Socket object for a more simple network packets sending and receiving. So it segments TCP traffic for packets and returns data in this view.
- Get the Socket object
- Create Mailbox by
Mailbox mailbox = new Mailbox(socket)
Network packets sending and receiving completes by mailbox.tick(); function in the NonBlocking mode. I.E. the best solution is to call this method with some interval (you can create a special thread to call this). mailbox.tick(); returns false when an error occurs or remote host is diconnected
- Create Packet object by
Packet packet = new Packet([yourdata : byte[]]);(for examplePacket packet = new Packet(Encoding.UTF8.GetBytes("Hello!"))) - To send packet call
mailbox.Send(packet) - Call
mailbox.Tick()
- Call
mailbox.Tick()in main or other thread with some time intervals - To receive packet on connected host use
mailbox.Next()to get a packet if any packet is received (null else) ormailbox.GetAllReceived()to get all received packets at the call time
!!! Don't forget to callmailbox.Tick()!!! - Received data bytes array is in packet.data field
Mailbox class has constructor: public Mailbox(Socket socket, int maxReceiveFragmentsPerTick = 64, int sendPacketsPerTick = 0, int maxPacketSize = 0)
Socket socket- socket that this object will be the facade ofint maxReceiveFragmentsPerTick- limit of received fragments per tickint sendPacketsPerTick- limit of packets, that can be sended per tickint maxPacketSize- limit of received packet size
!!! Do not use asynchronous packets listening with ticks !!!
Task StartListenAsync(int receivePacketsPerSecond = 0, CancellationToken cancellationToken = default)- start to receive and send packets asynchronouslyvoid StopListen(bool interruptSendingWhenAll = false)- stop receive and send packets asynchronously. IfinterruptSendingWhenAllis True, the packets sender will send all the packets in the send queue before stoppingTask StopListenAsync(bool interruptSendingWhenAll = false)- the same as theStopListenmethod, but returns a Task, that will be finished when the send and the receive tasks will be finishedvoid StopListenWait(bool interruptSendingWhenAll = false)- the same as theStopListenmethod, but blocks the call thread until the send and the receive tasks will be finishedTask<Packet> GetNextAsync(CancellationToken cancellationToken = default)- get the next packet or waitTask<IEnumerable<Packet>> GetAllReceivedAsync(CancellationToken cancellationToken = default)get all received packets if exist or waits for new packet otherwice
bool IsConnected- checks if socket is connected (Connected socket property)int SendQueueSize- get the number of currently processed packetsint ReceivedCount- get the number of received packets in the queueint SendQueueSize- get send queue sizevoid Close()- close socketbool IsSendQueueEmpty- checks if send queue is emptyvoid ClearReceived()- clears received packet queuevoid ClearReceivedQueue()- clears send packet queuevoid ClearAll()- clears both packet queuesPacket Packet.CloneDataRef()- returns new ready for sending Packet with some data ref
- You can set owner object of mailbox by
void SetOwner(IMailboxOwner)method and get it byTYPE GetOwner<TYPE>()method. - Owner object must implement IMailboxOwner interface and have MailboxSafe object
For example:
public class ClientInfo : IMailboxOwner {
public MailboxSafe MailboxSafe { get; } = new MailboxSafe();
}- Also call
mailbox.RemoveOwner()to remove owner object link. - Owner link methods are thread-safe, but don't use it too often. The purpose of these methods is to bind mailbox owner object in the start of handling
- Also you can use
GetMailbox,SetMailbox,RemoveMailboxIMailboxOwner's extension methods. They call similar methods in owned mailbox
(You can find the Test project in this repository MailboxShell solution) Lightweight example:
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(IPAddress.Parse(SERVER_IP), SERVER_PORT);
Mailbox mailbox = new Mailbox(socket);
while(true) {
string message = Console.ReadLine();
mailbox.Send(new Packet(Encoding.UTF8.GetBytes(message)));
while(true) {
mailbox.Tick();
Packet receivedPacket = mailbox.Next(); //Try to get the next packet
if(receivedPacket != null) {
Console.WriteLine($"Server response: \"{Encoding.UTF8.GetString(receivedPacket.data)}\"");
break;
}
Thread.sleep(1);
}
}Socket serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
serverSocket.Bind(new IPEndPoint(IPAddress.Parse(ip), port));
serverSocket.Listen(10);
Mailbox mailbox = new Mailbox(serverSocket.Accept());
while(true) {
mailbox.Tick(); //Tick to receive
foreach(Packet packet in mailbox.GetAllReceived()) {
string message = Encoding.UTF8.GetString(packet.data); //Get message from packet.data
mailbox.Send(new Packet(Encoding.UTF8.GetBytes("Echo: " + message))); //Send response
}
mailbox.Tick(); //Tick to send (but both ticks can be in one in this case)
Thread.sleep(1);
}private async Task handlePackets(Mailbox mailbox, CancellationToken cancellationToken) {
while(!cancellationToken.IsCancellationRequested) {
Packet packet = await mailbox.GetNextAsync(cancellationToken);
string responseString = Encoding.UTF8.GetString(packet.data);
Console.WriteLine($"Server response: \"{responseString}\"");
}
}
Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect(IPAddress.Parse(SERVER_IP), SERVER_PORT);
Mailbox mailbox = new Mailbox(socket);
CancellationTokenSource cts = new CancellationTokenSource();
Task listenTask = mailbox.StartListenAsync(cts.Token);
Task handlePacketsTask = mailbox.handlePackets(cts.Token);
Console.ReadKey();
cts.Cancel();
Task.WaitAll(listenTask, handlePacketsTask);