Initial commit
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
using IPClab._4.Models;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace IPClab._4.Services;
|
||||
|
||||
public class TcpServerService
|
||||
{
|
||||
private TcpListener? _listener;
|
||||
private CancellationTokenSource? _cts;
|
||||
private long _totalBytesReceived;
|
||||
private long _totalBytesSent;
|
||||
|
||||
public bool IsListening { get; private set; }
|
||||
|
||||
public async Task StartAsync(string ipAddress, int port, IProgress<NetworkEvent> progress)
|
||||
{
|
||||
if (IsListening) return;
|
||||
|
||||
_totalBytesReceived = 0;
|
||||
_totalBytesSent = 0;
|
||||
_cts = new CancellationTokenSource();
|
||||
|
||||
try
|
||||
{
|
||||
IPAddress localAddr = IPAddress.Parse(ipAddress);
|
||||
_listener = new TcpListener(localAddr, port);
|
||||
_listener.Start();
|
||||
IsListening = true;
|
||||
|
||||
progress.Report(new NetworkEvent { StatusText = "Listening", Message = $"Server started on {ipAddress}:{port}" });
|
||||
|
||||
// Run the acceptance loop on a background thread task
|
||||
_ = Task.Run(() => AcceptClientsAsync(_cts.Token, progress), _cts.Token);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
IsListening = false;
|
||||
progress.Report(new NetworkEvent { StatusText = "Faulted", Message = $"Failed to start server: {ex.Message}", IsError = true });
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AcceptClientsAsync(CancellationToken token, IProgress<NetworkEvent> progress)
|
||||
{
|
||||
while (!token.IsCancellationRequested)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Accept incoming connection
|
||||
TcpClient client = await _listener!.AcceptTcpClientAsync(token).ConfigureAwait(false);
|
||||
progress.Report(new NetworkEvent { StatusText = "Connected", Message = "Client connected to server." });
|
||||
|
||||
// Handle this client session
|
||||
await HandleClientSessionAsync(client, token, progress).ConfigureAwait(false);
|
||||
}
|
||||
catch (OperationCanceledException) when (token.IsCancellationRequested)
|
||||
{
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
progress.Report(new NetworkEvent { StatusText = "Listening", Message = $"Error accepting client: {ex.Message}", IsError = true });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandleClientSessionAsync(TcpClient client, CancellationToken token, IProgress<NetworkEvent> progress)
|
||||
{
|
||||
using (client)
|
||||
using (NetworkStream stream = client.GetStream())
|
||||
{
|
||||
// Quality Control Step: Enforce timeout boundaries
|
||||
stream.ReadTimeout = 5000;
|
||||
stream.WriteTimeout = 5000;
|
||||
|
||||
using (StreamReader reader = new StreamReader(stream, Encoding.UTF8))
|
||||
{
|
||||
while (!token.IsCancellationRequested && client.Connected)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Delimiter-based Framing: Read line until '\n' boundary
|
||||
string? receivedLine = await reader.ReadLineAsync(token).ConfigureAwait(false);
|
||||
|
||||
// TCP Disconnect Signal: stream returns null/0 bytes
|
||||
if (receivedLine == null) break;
|
||||
|
||||
long messageBytes = Encoding.UTF8.GetByteCount(receivedLine) + Environment.NewLine.Length;
|
||||
_totalBytesReceived += messageBytes;
|
||||
|
||||
progress.Report(new NetworkEvent
|
||||
{
|
||||
StatusText = "Data Received",
|
||||
Message = receivedLine,
|
||||
BytesTransferred = _totalBytesReceived
|
||||
});
|
||||
|
||||
// Lab 6 Echo/Response confirmation logic
|
||||
byte[] responseBytes = Encoding.UTF8.GetBytes($"ACK: {receivedLine}\n");
|
||||
await stream.WriteAsync(responseBytes, 0, responseBytes.Length, token).ConfigureAwait(false);
|
||||
_totalBytesSent += responseBytes.Length;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
progress.Report(new NetworkEvent { StatusText = "Disconnected", Message = $"Session terminated: {ex.Message}", IsError = true });
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
progress.Report(new NetworkEvent { StatusText = "Listening", Message = "Client disconnected clean." });
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
_cts?.Cancel();
|
||||
_listener?.Stop();
|
||||
IsListening = false;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user