Reputation: 378
TL;DR: I have a C# server which manages one client. What's the best approach for making it handle multiple clients?
Full explanation:
I'm implementing a C# socket server application which needs to handle multiple clients at the same time.
My logic is as follows:
The code I have so far only manages one client:
public partial class Form1 : Form
{
TcpListener listener;
Socket clientSock;
Thread listenThread, receiveThread;
string sendMsg, recvMsg;
byte[] sendMsgRaw, recvMsgRaw;
public Form1() {
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e) {
// Handler for onExit.
AppDomain.CurrentDomain.ProcessExit += new EventHandler(onExit);
}
private void listenButton_Click(object sender, EventArgs e) {
// Launch thread that listens for clients attempting to connect.
listener = new TcpListener(8888); // I know this method is deprecated, will fix.
listener.Start();
listenThread = new Thread(new ThreadStart(listenForClients));
listenThread.Start();
}
private void sendButton_Click(object sender, EventArgs e) {
// Send message to client.
sendMsg = sendTextbox.Text;
sendMsgRaw = Encoding.ASCII.GetBytes(sendMsg + "\r\n");
clientSock.Send(sendMsgRaw);
}
private void listenForClients() {
// Listen for connection attempts.
clientSock = listener.AcceptSocket();
disableButton(listenButton);
receiveThread = new Thread(new ThreadStart(readFromClient));
receiveThread.Start();
}
private void readFromClient() {
// Read response from client.
while(true) {
recvMsg = "";
recvMsgRaw = new byte[1024];
clientSock.Receive(recvMsgRaw);
recvMsg = Encoding.ASCII.GetString(recvMsgRaw);
appendRecvTextbox(recvMsg);
}
}
private void appendRecvTextbox(string message) {
// Append client's reply to a textbox.
if(InvokeRequired) {
this.Invoke(new Action<string>(appendRecvTextbox), new object[] { message });
return;
}
recvTextbox.AppendText(message + Environment.NewLine);
}
private void disableButton(Button btn) {
// Disable a button.
if(InvokeRequired) {
this.Invoke(new Action<Button>(disableButton), new object[] { btn });
return;
}
btn.Enabled = false;
}
private void onExit(object sender, EventArgs e) {
// Executed on program exit.
clientSock.Close();
}
}
Here is the screenshot of the form I have in mind: http://prntscr.com/azkaed
Basically when a listbox item (client) is selected, the received data area would change according to what has been received by that client.
And when that same listbox item (client) is selected and send a message, it would be sent to that client and that client alone (no multicast or something similar).
FYI later on I will implement a file transfer as well, following the same principles.
I'm not asking for you humble people to code my application for me, that is unproductive and I will learn nothing. I want to understand and process how all of this works. Obviously code samples which would help me understand are very, very welcome. Potential problems and questions:
So back to the main problem: In its current state, the app handles ONE client. How can I make it handle multiple clients? Do note that I chose multithreading because I'll have a limited amount of clients connected at a time - under 10 clients.
I know this is not an easy question I'm asking - but every answer will be deeply appreciated.
If it makes any difference, the clients will be written in an amalgam of languages like c/cpp, java, python, I'm even considering PHP. This is for the sole purpose of learning. But I doubt this matters. Clients seem far easier to program since there's less logic, so I do not require any help there.
Thank you in advance for any suggestion.
Upvotes: 3
Views: 4847
Reputation: 2340
First, have this link: http://www.codeproject.com/Articles/429144/Simple-Instant-Messenger-with-SSL-Encryption-in-Cs
Now I will anwser your questions:
There is no such thing like "too many threads". You can make your server that would have 1 Thread per request. This thread would read, and write data for that one request (This is how all webservices works, they usualy handles up to 100 threads per user). Performance wise. There is a thing called thread swapping, but dont bother with that.
You can make one thread per user, like in link above. Or you can go static, like webservices and do 1 thread per request.
You should look at threads not like an abstract thing, but more like an object. If you would always keep only one thread in one object you will never have a problem "knowing" witch thread is where. Ofc you have to remember about locks and stuff, but within one object one thread.
UDP does not guarantee that your packets will land where they were sent. TCP will at least try its best to do that. So to keep it simple go for TCP.
I have only clue, that you might use default one by accident.
Hope this will help.
Upvotes: 3