C
C#•8mo ago
Gipper

Help implementing multithreading in a distributed system, please?

I got a distributed system, meaning one solution that's a server and two which are clients. The objective is to use threads so that more than one client can communicate over TCP with the server simultaneously. I was told that I need to make it so there is some kind of code that makes it so different clients connect through different ports or the communication won't go well, but I really don't know. Any help you can give me? I know this isn't much to go on, but I'm trying to figure it out myself and feel free to ask questions and I'll do my best to answer.
29 Replies
Jimmacle
Jimmacle•8mo ago
what you probably want to do is have a listener loop whose job is to accept new clients and hand that connection off to individual threads/tasks for each client all your clients can connect to the same port on the server i don't recommend using plain threads, the task/async APIs are good for this
Gipper
GipperOP•8mo ago
Right now, I'm connecting by using on the client side:
TcpClient server = new TcpClient(serverIP, serverPort);
TcpClient server = new TcpClient(serverIP, serverPort);
I imagine I should use a constructor that just sends over the IP and not the port? On the server side:
TcpListener listener = new TcpListener(ipAddress, port);
listener.Start();
TcpListener listener = new TcpListener(ipAddress, port);
listener.Start();
Jimmacle
Jimmacle•8mo ago
no, the client still needs to know the port on the server but you don't need different ports for different clients TcpListener should have an Accept method that waits for a new connection then returns an object representing the connection to that client also use the async versions of methods if you can, here's an example from a similar project i have using plain Sockets instead of TcpListener
public async Task Run()
{
var stations = new Dictionary<EndPoint, Task>();
var listenIp = IPEndPoint.Parse("0.0.0.0:5555");
var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(listenIp);
listenSocket.Listen();
var pingTask = SendPings();

while (!_stopCts.IsCancellationRequested)
{
var stationSocket = await listenSocket.AcceptAsync(_stopCts.Token);
if (stationSocket.RemoteEndPoint is not null)
stations.Add(stationSocket.RemoteEndPoint, HandleStation(new NetworkStream(stationSocket, true)));
}
}
public async Task Run()
{
var stations = new Dictionary<EndPoint, Task>();
var listenIp = IPEndPoint.Parse("0.0.0.0:5555");
var listenSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
listenSocket.Bind(listenIp);
listenSocket.Listen();
var pingTask = SendPings();

while (!_stopCts.IsCancellationRequested)
{
var stationSocket = await listenSocket.AcceptAsync(_stopCts.Token);
if (stationSocket.RemoteEndPoint is not null)
stations.Add(stationSocket.RemoteEndPoint, HandleStation(new NetworkStream(stationSocket, true)));
}
}
where HandleStation is the method responsible for communicating with a single client
Gipper
GipperOP•8mo ago
listener has an AcceptTCPClient() method, which I am already using. Looking at the documentation there seems to also be no method named just Accept, however there are AcceptSocket(), AcceptSocketAsync() and AcceptTCPClientAsync()...
Jimmacle
Jimmacle•8mo ago
TcpClient is just a thin wrapper around Socket
Gipper
GipperOP•8mo ago
I think I already have the barebones of a listener loop similar to what you describe but it seems unfinished:
while (true)
{
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Cliente conectado.");
//HandleClient(client);
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
clientThread.Start(client);
}
while (true)
{
TcpClient client = listener.AcceptTcpClient();
Console.WriteLine("Cliente conectado.");
//HandleClient(client);
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClient));
clientThread.Start(client);
}
Jimmacle
Jimmacle•8mo ago
yeah, i wouldn't use raw threads though it'll work but tasks are the more modern way to do it
Gipper
GipperOP•8mo ago
my teacher may want me to though, idk he does specifically talk about threads not tasks
Jimmacle
Jimmacle•8mo ago
rip, just do it the crusty way then and keep in mind it's not how you should actually do it 😛
Gipper
GipperOP•8mo ago
tbf, I don't know that's what he wants, I'll have to ask him tomorrow but dos that loop do what I need? Like, is it connecting different clients to different ports?
Jimmacle
Jimmacle•8mo ago
you don't need different ports to accept multiple clients
Gipper
GipperOP•8mo ago
So, will it be able to successfully talk to different clients at the same time?
Jimmacle
Jimmacle•8mo ago
yes $tias
D.Mentia
D.Mentia•8mo ago
technically though, if it's not on different ports it ends up being async but not parallel I think? No two clients could really send at the same time, it'd have to 'wait' for one to finish before you could get the next message. If they specified that you need to use different ports, that may not be what you want. Though it's not at all typical in the real world to specify different ports or truly parallelize it, and what Jim's saying would be the real world solution - but if it's a class and a teacher telling you to do it, you better do what they say But if you need it on different ports and in parallel, just run two instances of the app with two different settings
Gipper
GipperOP•8mo ago
What would you consider proof that the communication is going well? I mean both solutions are firing fine and it seems to be saving the two clientID values simultaneously in a List like I programmed it to. In the debugger, in the parallell stacks view there seems to be two paralell threads taking place at the same time. Further testing is a little hard because the way this communication is fully completed is through editing of files, which I can't allow yet because of the problems with two threads accessing the same resource. I have to implement a mutex adequately (which I'll also need help with btw 😆 ) The two ports thing is because I asked a colleague of mine for advice and that's what he told me, but that's just how he did it
D.Mentia
D.Mentia•8mo ago
if it's all in the same app, a SemaphoreSlim would do the job, no need for a mutex (but mutex prob works too)
Gipper
GipperOP•8mo ago
Now I don't think the two ports thing is necessary, the teacher didnt say nothing about that I just thought that was the only way because I'm still learning the mutex thing on the other hand is a specific requirement
D.Mentia
D.Mentia•8mo ago
the main thing is just to use async. Use that everywhere, and it's all done
Lex Li
Lex Li•8mo ago
"I was told that I need to make it so there is some kind of code that makes it so different clients connect through different ports or the communication won't go well" is non-sense. Typical web servers (like Kestrel) work at a single port (like 80) very well with multiple clients. While you can always roll out your own framework via trials, you really analyze existing libraries/frameworks (Kestrel/SuperSockets) to understand their design and how they properly use threads.
Gipper
GipperOP•8mo ago
Thanks :Ok: I was told that different ports thing by a 20 year old CS student that is figuring this stuff out on his own and even then that's just my also very inexperienced interpretation of what he tried to sum up in 30 seconds, so I definitely wasn't taking it as an authoritative assessment at all, which is why I brought it up here for scrutiny. Is this relevant for my case? This isn't a web application, at least not in the conventional sense, it's supposed to mimic a very simple distributed system. Not saying it isn't, I just really don't know enough to judge Also, it's a specific requirement of this project that we only use System* .NET framework libraries, so would studying those other libs/frameworks really be helpful? Again, not a rhetorical question, I actually don't know
Jimmacle
Jimmacle•8mo ago
if the assignment is to do something with raw TCP connections then those libraries won't be helpful to you in my experience school assignments are best done exactly how the teacher wants them then learn actual good practices outside of school
Lex Li
Lex Li•8mo ago
Study the right way to use threads, and then you can apply the same pattern(s) to your project. There might be simpler samples, but frameworks used by production apps are clearly better source of information.
Gipper
GipperOP•8mo ago
Ok, so about the mutex implementation. This is a recreation of what I have:
private Mutex mutex = new Mutex();
//more code in between
mutex.WaitOne();
// code to access and possibly alter the shared resources(csv files)
mutex.ReleaseMutex();
private Mutex mutex = new Mutex();
//more code in between
mutex.WaitOne();
// code to access and possibly alter the shared resources(csv files)
mutex.ReleaseMutex();
will that work? Just looks really simple. It's really important that I can be sure and preferably demonstrate that access is being restricted and managed appropriately between all the different concurrent threads. @Lex Li @Jimmacle to make everything async, wouldn't I need to be working with and returning tasks? I can't use Tasks, teacher's orders :weirdChamp:
Jimmacle
Jimmacle•8mo ago
a whole mutex is probably unnecessary, SemaphoreSlim is enough if you want to control concurrent access to a resource in the same process is a literal Mutex a requirement?
Gipper
GipperOP•8mo ago
Yes, the teacher specifically talked about it repeatedly and it's all over the project protocol so yeah. I think in the second part of this project he's gonna want us to do more fancy stuff with shared resources which is why we're using Mutex despite it being overkill
Jimmacle
Jimmacle•8mo ago
man i hate school CS curriculum in that case what you have is fine
Gipper
GipperOP•8mo ago
please elaborate :Hmm:
Jimmacle
Jimmacle•8mo ago
it's almost always outdated and teaching weird practices that you wouldn't normally use
Want results from more Discord servers?
Add your server