Sometimes when reading a socket from the TcpClient class, the stream comes in without interpreting the data instantly. For example if I connect to an IRC server and I want to interpret the text in the channel to recognize commands. If somebody types a command, !time and !time is a valid function, it would write back to the server the current time.
The problem is if someone spams that same command !time at a high rate, the socket would be flooded. If someone else tried to execute !time it would not write back to the server until the while() loop finished reading the flooded socket stream. This could take minutes if not at all if the user kept spamming/flooding the command.
static void Connect(String hostname, int port)
{
try
{
socket = new TcpClient(hostname, port);
socket.ReceiveBufferSize = 4096;
Console.WriteLine("Successfully connected to " + hostname);
NetworkStream stream = socket.GetStream();
reader = new StreamReader(stream);
writer = new StreamWriter(stream);
write("USER " + username + " 8 * :" + description, writer);
write("NICK " + username, writer);
write("NS IDENTIFY " + password, writer);//Authenticate account
read(reader);//read the stream
reader.Close();
writer.Close();
stream.Close();
socket.Close();
}
catch
{
Console.WriteLine("Failed to connect to " + hostname);
}
}
read() function below:
static void read(StreamReader reader)
{
try
{
while (true)
{
interpret(reader.ReadLine());
}
}
catch
{
Console.WriteLine("Unable to read from server");
}
}
What could I do so the stream cannot be harmed if it were to be flooded? So that if someone did flood the stream with !time it would not stop other users from also seeing the time if they so typed !time.
Thank you.
Chatbot solution
You will have to process all the incoming text at least far enough to separate messages, and determine what user sent each message. Then you can split them into separate queues by user. You can either process the queues round-robin, or randomly. Or, you can implement a token bucket scheme, where every n seconds all users are given a certain number of tokens, and every command uses up a token. Users aren’t allowed to go above a limit of a certain number of tokens (p seconds worth of tokens they’re allowed to hoard). If there’s no token for that user when a command arrives, either throw it away or queue it for the next time tokens are given out.
Server-side solution
The other users have their own sockets, don’t they?
A backlog on one socket doesn’t prevent you from reading the others. You just have to write the application logic so it doesn’t get stuck reading from one, it goes round-robin and only reads more from the first after everyone has had a chance.
Typically you use some function like
selectorWaitAnywhich yield a list of ready sockets. Don’t always read from the first socket in the list, pick the one which most closely follows the last one you read, or else pick one randomly.