C
C#2mo ago
The Hyper

How to use Console.ReadLine() and do other stuff in the background?

title
33 Replies
The Hyper
The Hyper2mo ago
I've been trying threads but they only run once for some reason
Jimmacle
Jimmacle2mo ago
code in a thread has to be in a loop if you want it to keep running threads are relatively low level, Tasks are an abstraction over them
The Hyper
The Hyper2mo ago
sealed class Program
{
public static Thread main_thread;
public static List<Server> servers = new(1);
public static Server currentServer;
static void Main()
{
Console.WriteLine("Usage:\nstart <local ip address> <port>");
main_thread = new(new ThreadStart(HandleCommandInput));
main_thread.Start();
}

static void HandleCommandInput()
{
string input = Console.ReadLine();

Memory<string> input_chunks = input.Split(' ', StringSplitOptions.TrimEntries);

int input_chunks_length = input_chunks.Length;

foreach (Command command in CommandManager.commands)
{
if (command.cmd == input_chunks.Span[0])
{
command.action.Invoke(input_chunks);
break;
}
}

HandleCommandInput();
}
}
sealed class Program
{
public static Thread main_thread;
public static List<Server> servers = new(1);
public static Server currentServer;
static void Main()
{
Console.WriteLine("Usage:\nstart <local ip address> <port>");
main_thread = new(new ThreadStart(HandleCommandInput));
main_thread.Start();
}

static void HandleCommandInput()
{
string input = Console.ReadLine();

Memory<string> input_chunks = input.Split(' ', StringSplitOptions.TrimEntries);

int input_chunks_length = input_chunks.Length;

foreach (Command command in CommandManager.commands)
{
if (command.cmd == input_chunks.Span[0])
{
command.action.Invoke(input_chunks);
break;
}
}

HandleCommandInput();
}
}
using System;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Threading;

public sealed class Server
{

// Create a UDP socket
public UdpClient udpServer;
public string local_ip_address;
public ushort port;
public IPEndPoint clientEndPoint;
public Thread thread;
public CancellationTokenSource thread_token; // Create a token source.
public Server(in ushort port)
{
local_ip_address = "127.0.0.1";
this.port = port;
udpServer = new(port);
clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
}
public void Start()
{
IPAddress ipaddress = IPAddress.Parse(local_ip_address);
udpServer.Connect(ipaddress, port);

thread_token = new();

thread = new(() => Process(thread_token.Token));
thread.IsBackground = true;
thread.Start();

Console.WriteLine($"Server #{Program.servers.IndexOf(Program.currentServer) + 1} is running. Waiting for messages...");

}
public void Stop()
{
thread_token.Cancel();
udpServer.Dispose();
}
public void Process(in CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("SERVER PROCESSING");
ReadOnlySpan<byte> receivedBytes = udpServer.Receive(ref clientEndPoint);
Vector3 receivedVector = BytesToVector3(receivedBytes);

// Print the received Vector3
Console.WriteLine($"Received Vector3 from {clientEndPoint}: {receivedVector}");
}
}
// Deserialize bytes into a Vector3
static Vector3 BytesToVector3(ReadOnlySpan<byte> bytes)
{
Vector3 vec;
vec.X = BitConverter.ToSingle(bytes.Slice(0, 4));
vec.Y = BitConverter.ToSingle(bytes.Slice(4, 4));
vec.Z = BitConverter.ToSingle(bytes.Slice(8, 4));
return vec;
}

}
using System;
using System.Net;
using System.Net.Sockets;
using System.Numerics;
using System.Threading;

public sealed class Server
{

// Create a UDP socket
public UdpClient udpServer;
public string local_ip_address;
public ushort port;
public IPEndPoint clientEndPoint;
public Thread thread;
public CancellationTokenSource thread_token; // Create a token source.
public Server(in ushort port)
{
local_ip_address = "127.0.0.1";
this.port = port;
udpServer = new(port);
clientEndPoint = new IPEndPoint(IPAddress.Any, 0);
}
public void Start()
{
IPAddress ipaddress = IPAddress.Parse(local_ip_address);
udpServer.Connect(ipaddress, port);

thread_token = new();

thread = new(() => Process(thread_token.Token));
thread.IsBackground = true;
thread.Start();

Console.WriteLine($"Server #{Program.servers.IndexOf(Program.currentServer) + 1} is running. Waiting for messages...");

}
public void Stop()
{
thread_token.Cancel();
udpServer.Dispose();
}
public void Process(in CancellationToken token)
{
while (!token.IsCancellationRequested)
{
Console.WriteLine("SERVER PROCESSING");
ReadOnlySpan<byte> receivedBytes = udpServer.Receive(ref clientEndPoint);
Vector3 receivedVector = BytesToVector3(receivedBytes);

// Print the received Vector3
Console.WriteLine($"Received Vector3 from {clientEndPoint}: {receivedVector}");
}
}
// Deserialize bytes into a Vector3
static Vector3 BytesToVector3(ReadOnlySpan<byte> bytes)
{
Vector3 vec;
vec.X = BitConverter.ToSingle(bytes.Slice(0, 4));
vec.Y = BitConverter.ToSingle(bytes.Slice(4, 4));
vec.Z = BitConverter.ToSingle(bytes.Slice(8, 4));
return vec;
}

}
using System;

public static class CommandManager
{
public static HashSet<Command> commands = new()
{
new Command("start", (args) =>
{
int args_length = args.Length;
if (args_length <= 2)
{
Program.currentServer = new Server(4444);
Program.servers.Add(Program.currentServer);
Program.currentServer.Start();
}
else
{
ushort port = Convert.ToUInt16(args.Span[2]);
Program.currentServer = new Server(in port);
Program.servers.Add(Program.currentServer);
Program.currentServer.Start();
}
}),
new Command("port", (args) =>
{
if (Program.currentServer == null) return;
Console.WriteLine($"Port of Server #{Program.servers.IndexOf(Program.currentServer) + 1} = {Program.currentServer.port}");
}),
new Command("stop", (args) =>
{
Program.currentServer.Stop();
}),
};
}

public readonly struct Command
{
public readonly string cmd;
public readonly Action<Memory<string>> action;

public Command(string cmd, Action<Memory<string>> action)
{
this.cmd = cmd;
this.action = action;

}
}
using System;

public static class CommandManager
{
public static HashSet<Command> commands = new()
{
new Command("start", (args) =>
{
int args_length = args.Length;
if (args_length <= 2)
{
Program.currentServer = new Server(4444);
Program.servers.Add(Program.currentServer);
Program.currentServer.Start();
}
else
{
ushort port = Convert.ToUInt16(args.Span[2]);
Program.currentServer = new Server(in port);
Program.servers.Add(Program.currentServer);
Program.currentServer.Start();
}
}),
new Command("port", (args) =>
{
if (Program.currentServer == null) return;
Console.WriteLine($"Port of Server #{Program.servers.IndexOf(Program.currentServer) + 1} = {Program.currentServer.port}");
}),
new Command("stop", (args) =>
{
Program.currentServer.Stop();
}),
};
}

public readonly struct Command
{
public readonly string cmd;
public readonly Action<Memory<string>> action;

public Command(string cmd, Action<Memory<string>> action)
{
this.cmd = cmd;
this.action = action;

}
}
Jimmacle
Jimmacle2mo ago
HandleCommandInput should not be recursive, it should just have a loop in it
The Hyper
The Hyper2mo ago
ohh
Jimmacle
Jimmacle2mo ago
otherwise you're going to hit a stack overflow because it keeps calling itself
The Hyper
The Hyper2mo ago
I thought Console.Readline() would stop the rest of the function from executing
Jimmacle
Jimmacle2mo ago
it does until a line is received from the console that's unrelated
The Hyper
The Hyper2mo ago
I mean I used it as a recursion break
Jimmacle
Jimmacle2mo ago
besides that not doing what you think, i don't think you want that anyway don't you want to handle commands until the program exits?
The Hyper
The Hyper2mo ago
yes ofc, the input stuff works properly for me, my main problem is that the Server thread runs only once hold on wrong ss
The Hyper
The Hyper2mo ago
started debugging:
No description
The Hyper
The Hyper2mo ago
entered the command "start"
No description
The Hyper
The Hyper2mo ago
the SERVER PROCESSING runs only once where it should run continously, on another thread
Jimmacle
Jimmacle2mo ago
are you sure that's the case and it's not getting stuck somewhere in that loop?
The Hyper
The Hyper2mo ago
but the Console.Readline() works fine
No description
The Hyper
The Hyper2mo ago
hmm
Jimmacle
Jimmacle2mo ago
because i don't see it print out the second message after receiving data
The Hyper
The Hyper2mo ago
the only problem could be this line "while (!token.IsCancellationRequested)" otherwise the loop worked fine before I started trying all this multi-threading mess idk I'm just so lost can't find anything close to this in google
Jimmacle
Jimmacle2mo ago
have you set breakpoints in that code to make sure it actually gets through one iteration of the loop?
The Hyper
The Hyper2mo ago
I made it while(true) and it still runs only once I mean it prints "SERVER PROCESSING" only once
Jimmacle
Jimmacle2mo ago
but have you actually determined it's running once to begin with? or is some code in there blocking forever? yeah, so it's never finishing the first loop because you would expect to see that other message print out too are you sending data to that endpoint?
The Hyper
The Hyper2mo ago
only receiving data
Jimmacle
Jimmacle2mo ago
well if you're not sending anything to the program it will sit there and wait
The Hyper
The Hyper2mo ago
but not actually receiving any data rn oh wtf
Jimmacle
Jimmacle2mo ago
also, this is a really unreliable way to write network code you're using UDP but don't seem to have any reliability or framing implemented so there's 0 guarantee that a single call to recieve will give you all the data you're expecting and in the right order it's explained in the docs https://learn.microsoft.com/en-us/dotnet/api/system.net.sockets.udpclient.receive?view=net-8.0#examples
The Hyper
The Hyper2mo ago
yeah, I'm just testing and learning networking, but I'm calling the Console.WriteLine() before the doing the networking stuff ohhh
Jimmacle
Jimmacle2mo ago
do yourself a favor and use TCP instead before you run into other issues caused by using an unreliable protocol
The Hyper
The Hyper2mo ago
can't, making a game server I must use udp
Jimmacle
Jimmacle2mo ago
why does that matter says who? the protocol you choose should be based on actual performance and reliability requirements, not "it's a game"
The Hyper
The Hyper2mo ago
for rapidly sent informations of the game, such as the player's position, I gotta use udp due to its less latency
Jimmacle
Jimmacle2mo ago
are you writing a game networking system from scratch? because that is significantly more complicated than you might think
The Hyper
The Hyper2mo ago
basically trying to yeah yeah, client interpolation, buffering all the data etc etc I didn't know that receive() method was stopping the execution, thanks