Last active
January 10, 2024 14:21
Multithread TCP Sever & HTTPClient written in C#(Managed Code)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Buffers; | |
string serverUrl = "http://localhost:2305"; | |
int numRequests = 100000; | |
int concurrency = 100; | |
using HttpClient client = new(); | |
using var semaphore = new SemaphoreSlim(concurrency); | |
var tasks = new Task[numRequests]; | |
for (int i = 0; i < numRequests; i++) | |
tasks[i] = SendRequestAsync(client, serverUrl, semaphore); | |
await Task.WhenAll(tasks); | |
static async Task SendRequestAsync(HttpClient client, string url, SemaphoreSlim semaphore) | |
{ | |
// Use MemoryPool<byte> to rent a buffer | |
using var memoryPool = MemoryPool<byte>.Shared; | |
var rentMemory = memoryPool.Rent(1024).Memory; | |
await semaphore.WaitAsync(); | |
try | |
{ | |
var watch = System.Diagnostics.Stopwatch.StartNew(); | |
using HttpResponseMessage response = await client.GetAsync(url); | |
using var stream = await response.Content.ReadAsStreamAsync(); | |
var endofstrem = await stream.ReadAsync(rentMemory); | |
var servermsg = System.Text.Encoding.UTF8.GetString(rentMemory.Span[..endofstrem]); | |
watch.Stop(); | |
Console.WriteLine($"Status Code: {response.StatusCode}, Message response: {servermsg} Duration: {watch.ElapsedMilliseconds} ms"); | |
} | |
finally | |
{ | |
semaphore.Release(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Buffers; | |
using System.Diagnostics; | |
using System.Net; | |
using System.Net.Sockets; | |
using System.Text; | |
using System.Threading.Channels; | |
var ipEndPoint = new IPEndPoint(IPAddress.Any, 2305); | |
using TcpListener listener = new(ipEndPoint); | |
var channel = Channel.CreateBounded<TcpClient>(100); | |
try | |
{ | |
//listern with backlog (pending connection) | |
listener.Start(); | |
Console.WriteLine("Server is listening on port 2305..."); | |
while (true) | |
{ | |
Console.WriteLine("Waiting for a client to connect..."); | |
TcpClient handler = await listener.AcceptTcpClientAsync().ConfigureAwait(true); | |
Console.WriteLine("Client connected."); | |
await channel.Writer.WriteAsync(handler); | |
// handle multiple requests | |
_ = HandleRequestAsync(channel.Reader); | |
} | |
} | |
finally | |
{ | |
listener.Stop(); | |
} | |
static async Task HandleRequestAsync(ChannelReader<TcpClient> channel) | |
{ | |
// Use MemoryPool<byte> to rent a buffer | |
using var memoryPool = MemoryPool<byte>.Shared; | |
var rentMemory = memoryPool.Rent(1024).Memory; | |
await foreach (var handler in channel.ReadAllAsync()) | |
{ | |
Stopwatch sw = Stopwatch.StartNew(); | |
using NetworkStream stream = handler.GetStream(); | |
var remoteEndPoint = handler.Client.RemoteEndPoint; | |
int bytesRead = await stream.ReadAsync(rentMemory); | |
Encoding.UTF8.GetString(rentMemory.Span[..bytesRead]); | |
Console.WriteLine($"Received from client port {remoteEndPoint}"); | |
Console.WriteLine("Processing the request.."); | |
await Task.Delay(5000); | |
var clientMessage = $"HTTP/1.1 200 OK\r\n\r\nHello, World! 📅 {DateTime.Now} 🕛\r\n".AsMemory(); | |
var sendMessaggeBytes = Encoding.UTF8.GetBytes(clientMessage.Span, rentMemory.Span); | |
await stream.WriteAsync(rentMemory[..clientMessage.Length]); | |
Console.WriteLine($"Sent message.{Encoding.UTF8.GetString(rentMemory.Span[..clientMessage.Length])}"); | |
handler.Close(); | |
sw.Stop(); | |
Console.WriteLine($"Connection handled time: {sw.ElapsedMilliseconds} ms"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment