Click here to Skip to main content
15,885,869 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
Server starts up, and client connects, it is multithreaded, and the main point is to broadcast the message, that it got fro the server. However, when a client disconnects(gets forcibly closed), it still tries to run the ClientListener method(underlined)

SERVER CODE:
C#
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Threading;

namespace Server
{
    class Program
    {
        private static TcpListener tcpListener;
        private static List<TcpClient> tcpClientsList = new List<TcpClient>();
        private static Boolean wroteshutdownonce = false;

        static void Main(string[] args)
        {
            Console.Write("Please input, what the port should be: ");
            int port = Convert.ToInt32(Console.ReadLine());

            tcpListener = new TcpListener(IPAddress.Any, port);
            tcpListener.Start();

            Console.Write(time());
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("Server started");

            while (true)
            {
                TcpClient tcpClient = tcpListener.AcceptTcpClient();
                tcpClientsList.Add(tcpClient);

                Thread thread = new Thread(ClientListener);
                thread.Start(tcpClient);
                wroteshutdownonce = false;
            }
        }

        public static void ClientListener(object obj)
        {
            TcpClient tcpClient = (TcpClient)obj;
            StreamReader reader = new StreamReader(tcpClient.GetStream());

            Console.Write(time());
            Console.ForegroundColor = ConsoleColor.White;
            Console.WriteLine("Client connected");
            while (true)
            {
                //try
                //{
                    string message = reader.ReadLine();
                    BroadCast(message, tcpClient);
                    Console.Write(time());
                    Console.ForegroundColor = ConsoleColor.White;
                    Console.WriteLine(message);
                //} catch
                //{
                    /*if (wroteshutdownonce == false)
                    {
                        Console.ForegroundColor = ConsoleColor.DarkRed;
                        Console.WriteLine("One Client has been shut down!!");
                        Console.ForegroundColor = ConsoleColor.White;
                        tcpClient.Close();
                        wroteshutdownonce = true;
                    }*/
                //}
            }
        }

        public static void BroadCast(string msg, TcpClient excludeClient)
        {
            foreach (TcpClient client in tcpClientsList)
            {
                if (client != excludeClient)
                {
                    StreamWriter sWriter = new StreamWriter(client.GetStream());
                    sWriter.WriteLine(msg);
                    sWriter.Flush();
                }
            }
        }
        static string time()
        {
            String datetime = Convert.ToString(DateTime.Now);
            string[] splittedTime = datetime.Split(' ');
            datetime = "[" + splittedTime[0] + splittedTime[1] + splittedTime[2] + " " + splittedTime[3] + "] ";
            Console.ForegroundColor = ConsoleColor.Green;
            return datetime;
        }
    }
}


CLIENT CODE:
C#
using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Text;
using System.Threading;

namespace BroadcastClient
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.Write("Type in your username: ");
            String username = Console.ReadLine();
            try
            {
                TcpClient tcpClient = new TcpClient("127.0.0.1", 5001);
                Console.WriteLine("Connected to server.");
                Console.WriteLine("");

                Thread thread = new Thread(Read);
                thread.Start(tcpClient);

                StreamWriter sWriter = new StreamWriter(tcpClient.GetStream());

                while (true)
                {
                    if (tcpClient.Connected)
                    {
                        string input = Console.ReadLine();
                        sWriter.WriteLine(username+";" + input);
                        sWriter.Flush();
                    }
                }

            }
            catch (Exception e)
            {
                Console.Write(e.Message);
            }

            Console.ReadKey();
        }

        static void Read(object obj)
        {
            TcpClient tcpClient = (TcpClient)obj;
            StreamReader sReader = new StreamReader(tcpClient.GetStream());

            while (true)
            {
                try
                {
                    string message = sReader.ReadLine();
                    Console.WriteLine(message);
                }
                catch (Exception e)
                {
                    Console.WriteLine(e.Message);
                    break;
                }
            }
        }
    }
}


What I have tried:

It keep dropping the following error:
System.IO.IOException
HRESULT = 0x80131620
Message = Cannot read transport connection: The existing connection was forcibly closed by the remote host.
Source = System
StackTrace:
at System.Net.Sockets.NetworkStream.Read (Byte [] buffer, Int32 offset, Int32 size)
at System.IO.StreamReader.ReadBuffer ()
at System.IO.StreamReader.ReadLine ()
at Server.Program.ClientListener (Object obj) in C: \ Users \ username \ Desktop \ C # Broadcasting \ BroadcastServer \ Program.cs: line 52
at System.Threading.ThreadHelper.ThreadStart_Context (Object state)
at System.Threading.ExecutionContext.RunInternal (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
at System.Threading.ExecutionContext.Run (ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.ThreadHelper.ThreadStart (Object obj)

Inner Exception 1:
SocketException: The existing connection was forcibly closed by the remote host



TRIED TO:
- break; the method
- create wroteshutdownonce variable, so it won't run the tcpClient.Close(); command again.
- tcpClient.Close();


Thank you for the help!
Posted
Updated 21-Jan-20 20:01pm

See example here, the client.Close(); must be outside the While loop:
TcpListener Class (System.Net.Sockets) | Microsoft Docs[^]

With a While loop like this:
// Loop to receive all the data sent by the client.
while((i = stream.Read(bytes, 0, bytes.Length))!=0)
{
  // Translate data bytes to a ASCII string.
  data = System.Text.Encoding.ASCII.GetString(bytes, 0, i);
  Console.WriteLine("Received: {0}", data);
)

// Shutdown and end connection
client.Close();


For the server to know when to stop listening, your client could send a special message, but this would be a bit unusual as servers normally keep listening.
 
Share this answer
 
v3
Comments
Csabatom 19-Nov-19 14:49pm    
Tried it as you said, it looks like this:

public static void ClientListener(object obj)
{
TcpClient tcpClient = (TcpClient)obj;
StreamReader reader = new StreamReader(tcpClient.GetStream());

Console.Write(time());
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine("Client connected");
while (true)
{
string message = reader.ReadLine();
BroadCast(message, tcpClient);
Console.Write(time());
Console.ForegroundColor = ConsoleColor.White;
Console.WriteLine(message);
}
tcpClient.Close();
}

Printing the same error message :(
RickZeeland 19-Nov-19 15:07pm    
The point is that you can not keep reading from the stream when all data is read, see the updated solution for an example While loop.
Csabatom 19-Nov-19 15:20pm    
Tried, but not working. I think, i'm the biggest noob xD
RickZeeland 19-Nov-19 15:25pm    
This is not one of the easiest things to start with, maybe you can try the example first and gradually expand it with your own code. Good luck and don't give up too easily !
Csabatom 19-Nov-19 15:32pm    
Thanks for the help anyway :)
When your client disconnects you should get a disconnect event on your server. Use it to terminate the the thread of the client on the server. Then you will not be trying to access it again until it reconnects.

However, I am not sure the client disconnect is causing the error. In your while loop you are continuing to assume there is a new connection, and then sending to it. What if there is no new connection? I would also test for an active connection prior to reading from it as you do in your broadcast section.

I would try to make your connections active on events instead of on a loop.

Check this for more information.
https://www.codeproject.com/Articles/1415/Introduction-to-TCP-client-server-in-C

Also
https://social.msdn.microsoft.com/Forums/en-US/802a98c0-9d56-4416-9c3f-954616ed4754/how-to-get-socket-events-in-c">How to get socket events in C#

Another option would be to include a way to track ID each client. The use of creating GUID here would help. You create it when the client connects and it will keep track of each client and their status. You could create a "client connect class" with the ip and status of all connected clients and then on the disconnect event, set the status to "offline" or other flag, and test for it before calling the listener (or the broadcast) methods. Or on disconnect you could remove the GUID and if it does not exist, then don't call the methods.

Hope this points you in the correct direction.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900