Urko Sanchez Ortiz
Urko Sanchez Ortiz

Reputation: 311

Multithread message send on TCP server

I need to make a broadcast of the clients connected to the server using TcpClient. Currently I have a for that goes through the whole list of clients and they receive the message one by one. But there is some time between messages, so the clients do not receive the message simultaneously. I think that using a multithreading or coroutines works, someone can advise me? I attach the function code of the broadcast

Thank you all

public void broadCast(string sendMsg)
{
    foreach (User user in clientList)
    {
        if (user.tcpClient != null)
        {
            m_NetStream = user.tcpClient.GetStream();

            if (m_NetStream != null)
            {
                byte[] msgOut = Encoding.ASCII.GetBytes(sendMsg);
                m_NetStream.Write(msgOut, 0, msgOut.Length);
            }
            else
            {
                ServerLog("Socket Error: Start at least one client first", Color.red);
                return;
            }
        }
    }
}

Upvotes: 0

Views: 328

Answers (1)

Damien_The_Unbeliever
Damien_The_Unbeliever

Reputation: 239636

If you want to send to multiple clients simultaneously, I'd suggest using the Async variants of Write. I'd also, as suggested in the comments, move creating the buffer to send out of the loop.

At the moment you don't return from broadCast until all of the messages are sent, which I've implemented below as a WaitAll, but that can be skipped or this method made async if that's more appropriate.

public void broadCast(string sendMsg)
{
    var pendingSends = new List<Task>();
    byte[] msgOut = Encoding.ASCII.GetBytes(sendMsg);
    foreach (User user in clientList)
    {
        if (user.tcpClient != null)
        {
            m_NetStream = user.tcpClient.GetStream();

            if (m_NetStream != null)
            {

                pendingSends.Add(m_NetStream.WriteAsync(msgOut, 0, msgOut.Length));
            }
            else
            {
                ServerLog("Socket Error: Start at least one client first", Color.red);
            }
        }
    }
    Task.WaitAll(pendingSends.ToArray());
}

(Side note, not sure that error logging is in the right place. I'd have expected it to trigger on clientList being empty instead)

Note that I didn't do anything involving threads here - this task seems to be inherently I/O bound, limited by how fast we can send data over the network. Introducing more threads wouldn't change that.

Finally, I'll repeat from the comments:

be aware that TCP is an endless stream of bytes, not messages. I'm not seeing you do anything to assist the receiver with determining the extent of your message (by e.g. sending the length first, or delimiters, or other message framing techniques)

Upvotes: 1

Related Questions