tcp server chat

Asked

Viewed 117 times

-3

Here’s the thing, I have a tcp server for chat. whenever I turn on the server and then close the form, the program gives error because it is in an infinite loop in this part of the code:

while (Connected)
{
    Sendtxtbox.Enabled = true;
    // Mostra a mensagem na TextBox.
    try
    {

        this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { 
            srReceiver.ReadLine() 
        });
    }
    catch
    { }
}

How can I break the loop when the tcp server closes?

All code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;

namespace Random
{
    public partial class Chat : Form
    {
        private delegate void UpdateStatusCallback(string strMessage);
        private string UserName = "Desconhecido";
        private StreamWriter swSender;
        private StreamReader srReceiver;
        private TcpClient tcpServer;
        private delegate void UpdateLogCallback(string strMessage);
        private delegate void CloseConnectionCallback(string strReason);
        private Thread thrMessaging;
        private IPAddress ipAddr;
        private bool Connected;
        private ChatServer mainServer;

        public Chat()
        {
            InitializeComponent();

        }
        private void InitializeConnection()
        {
            btnLiga.Enabled = false;
            // Parse the server's IP address out of the TextBox
            IPAddress ipAddr = IPAddress.Parse(Iptxtbox.Text);
            // Create a new instance of the ChatServer object
            mainServer = new ChatServer(ipAddr);


            // Hook the StatusChanged event handler to mainServer_StatusChanged
            //ChatServer.StatusChanged += new StatusChangedEventHandler(mainServer_StatusChanged);

            // Start listening for connections
            mainServer.StartListening();
            // Show that we started to listen for connections
            Logtxtbox.AppendText("Conectado...\r\n");
            // Analise o IP da TextBox para um IPAddress.
            ipAddr = IPAddress.Parse(Iptxtbox.Text);
            // Começa uma nova começao TCP para o chat servidor.
            tcpServer = new TcpClient();
            tcpServer.Connect(ipAddr, 1177);
            Connected = true;
            UserName = Usertxtbox.Text;
            Iptxtbox.Enabled = false;
            Usertxtbox.Enabled = false;
            Logtxtbox.Enabled = true;
            Sendbtn.Enabled = true;
            btnLiga.Text = "Disconnectar";
            // Envia o username pretendido para o server.
            swSender = new StreamWriter(tcpServer.GetStream());
            swSender.WriteLine(Usertxtbox.Text);
            swSender.Flush();
            // Começa uma tarefa para receber mensagens e adicionar na comunicaçao.
            thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
            thrMessaging.Start();

        }

        private void btnLiga_Click(object sender, EventArgs e)
        {
            if (Usertxtbox.Text.Length == 0)
                MessageBox.Show("Introduza um nick valido.", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
            {
                // Se nao estivermos conectados mas á espera de conectar.
                if (Connected == false)
                {
                    // Conecta.
                    InitializeConnection();
                }
                else // Se estivermos conectados, disconecta.
                {
                    CloseConnection("Disconectado.");
                }
            }

        }
        //public void mainServer_StatusChanged(object sender, StatusChangedEventArgs e)
        //{
        //    // Call the method that updates the form
        //    this.Invoke(new UpdateStatusCallback(this.UpdateStatus), new object[] { e.EventMessage });
        //}
        ////private void UpdateStatus(string strMessage)
        ////{
        ////    // Updates the log with the message
        ////    Logtxtbox.AppendText(strMessage + "\r\n");
        ////}
        private void SendMessage()
        {
            if (Sendtxtbox.Lines.Length >= 1)
            {
                swSender.WriteLine(Sendtxtbox.Text);
                swSender.Flush();
                Sendtxtbox.Lines = null;
            }
            Sendtxtbox.Text = "";
        }


        private void Sendbtn_Click(object sender, EventArgs e)
        {
            SendMessage();
        }
        private void ReceiveMessages()
        {
            // Recebe a resposta do servidor.
            srReceiver = new StreamReader(tcpServer.GetStream());
            string ConResponse = srReceiver.ReadLine();
            // Se o primeiro caracter da resposta for 1, a coneçao é feita com sucesso.
            if (ConResponse[0] == '1')
            {
                // Actualiza a form para dizer que nao estamos conectados agora.
                this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { "Conectado! :D" });
            }
            else
            {
                string Reason = "Nao conectado: ";
                Reason += ConResponse.Substring(2, ConResponse.Length - 2);
                // Actualiza a form com a razao do qual nos nao poderiamos estar conectados.
                this.Invoke(new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });
                // Exit the method
                return;
            }
            // Enquanto nos estamos conectados, le as linhas do servidor.
            while (Connected)
            {
                Sendtxtbox.Enabled = true;
                // Mostra a mensagem na TextBox.
                try
                {

                    this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
                }
                catch
                { }
            }
        }
        private void UpdateLog(string strMessage)
        {

            Logtxtbox.AppendText(strMessage + "\r\n");
        }
        private void CloseConnection(string Reason)
        {

            // Mostra o porque da coneçao ter fechado.
            Logtxtbox.AppendText(Reason + "\r\n");
            // Activa e desactiva os controlos apropriados da form.
            Iptxtbox.Enabled = true;
            Usertxtbox.Enabled = true;
            Sendtxtbox.Enabled = false;
            Sendbtn.Enabled = false;
            // Fecha os objectos.
            Connected = false;
            swSender.Close();
            srReceiver.Close();
            tcpServer.Close();
            //mainServer.CloseListening();
            btnLiga.Text = "Conectar";
        }

        private void Chat_FormClosed(object sender, FormClosedEventArgs e)
        {

           // CloseConnection("Disconectado.");
            Connection con = new Connection(tcpServer);
            con.CloseConnection();
            this.Hide();
        }

    }
}

This is the second part:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections;

namespace Random
{
    // Holds the arguments for the StatusChanged event
    public class StatusChangedEventArgs : EventArgs
    {
        // The argument we're interested in is a message describing the event
        private string EventMsg;

        // Property for retrieving and setting the event message
        public string EventMessage
        {
            get
            {
                return EventMsg;
            }
            set
            {
                EventMsg = value;
            }
        }

        // Constructor for setting the event message
        public StatusChangedEventArgs(string strEventMsg)
        {
            EventMsg = strEventMsg;
        }
    }

    // This delegate is needed to specify the parameters we're passing with our event
    public delegate void StatusChangedEventHandler(object sender, StatusChangedEventArgs e);

    class ChatServer
    {
        // This hash table stores users and connections (browsable by user)
        public static Hashtable htUsers = new Hashtable(30); // 30 users at one time limit
        // This hash table stores connections and users (browsable by connection)
        public static Hashtable htConnections = new Hashtable(30); // 30 users at one time limit
        // Will store the IP address passed to it
        private IPAddress ipAddress;
        private TcpClient tcpClient;
        // The event and its argument will notify the form when a user has connected, disconnected, send message, etc.
        public static event StatusChangedEventHandler StatusChanged;
        private static StatusChangedEventArgs e;

        // The constructor sets the IP address to the one retrieved by the instantiating object
        public ChatServer(IPAddress address)
        {
            ipAddress = address;
        }

        // The thread that will hold the connection listener
        private Thread thrListener;

        // The TCP object that listens for connections
        private TcpListener tlsClient;

        // Will tell the while loop to keep monitoring for connections
        bool ServRunning = false;

        // Add the user to the hash tables
        public static void AddUser(TcpClient tcpUser, string strUsername)
        {
            // First add the username and associated connection to both hash tables
            ChatServer.htUsers.Add(strUsername, tcpUser);
            ChatServer.htConnections.Add(tcpUser, strUsername);

            // Tell of the new connection to all other users and to the server form
            SendAdminMessage(htConnections[tcpUser] + " has joined us");
        }

        // Remove the user from the hash tables
        public static void RemoveUser(TcpClient tcpUser)
        {
            // If the user is there
            if (htConnections[tcpUser] != null)
            {
                // First show the information and tell the other users about the disconnection
                SendAdminMessage(htConnections[tcpUser] + " has left us");

                // Remove the user from the hash table
                ChatServer.htUsers.Remove(ChatServer.htConnections[tcpUser]);
                ChatServer.htConnections.Remove(tcpUser);
            }
        }

        // This is called when we want to raise the StatusChanged event
        public static void OnStatusChanged(StatusChangedEventArgs e)
        {
            StatusChangedEventHandler statusHandler = StatusChanged;
            if (statusHandler != null)
            {
                // Invoke the delegate
                statusHandler(null, e);
            }
        }

        // Send administrative messages
        public static void SendAdminMessage(string Message)
        {
            StreamWriter swSenderSender;

            // First of all, show in our application who says what
            e = new StatusChangedEventArgs("Administrator: " + Message);
            OnStatusChanged(e);

            // Create an array of TCP clients, the size of the number of users we have
            TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];
            // Copy the TcpClient objects into the array
            ChatServer.htUsers.Values.CopyTo(tcpClients, 0);
            // Loop through the list of TCP clients
            for (int i = 0; i < tcpClients.Length; i++)
            {
                // Try sending a message to each
                try
                {
                    // If the message is blank or the connection is null, break out
                    if (Message.Trim() == "" || tcpClients[i] == null)
                    {
                        continue;
                    }
                    // Send the message to the current user in the loop
                    swSenderSender = new StreamWriter(tcpClients[i].GetStream());
                    swSenderSender.WriteLine("Administrator: " + Message);
                    swSenderSender.Flush();
                    swSenderSender = null;
                }
                catch // If there was a problem, the user is not there anymore, remove him
                {
                    RemoveUser(tcpClients[i]);
                }
            }
        }

        // Send messages from one user to all the others
        public static void SendMessage(string From, string Message)
        {
            StreamWriter swSenderSender;

            // First of all, show in our application who says what
            e = new StatusChangedEventArgs(From + " says: " + Message);
            OnStatusChanged(e);

            // Create an array of TCP clients, the size of the number of users we have
            TcpClient[] tcpClients = new TcpClient[ChatServer.htUsers.Count];
            // Copy the TcpClient objects into the array
            ChatServer.htUsers.Values.CopyTo(tcpClients, 0);
            // Loop through the list of TCP clients
            for (int i = 0; i < tcpClients.Length; i++)
            {
                // Try sending a message to each
                try
                {
                    // If the message is blank or the connection is null, break out
                    if (Message.Trim() == "" || tcpClients[i] == null)
                    {
                        continue;
                    }
                    // Send the message to the current user in the loop
                    swSenderSender = new StreamWriter(tcpClients[i].GetStream());
                    swSenderSender.WriteLine(From + "  diz: " + Message);
                    swSenderSender.Flush();
                    swSenderSender = null;
                }
                catch // If there was a problem, the user is not there anymore, remove him
                {
                    RemoveUser(tcpClients[i]);
                }
            }
        }

        public void StartListening()
        {

            // Get the IP of the first network device, however this can prove unreliable on certain configurations
            IPAddress ipaLocal = ipAddress;

            // Create the TCP listener object using the IP of the server and the specified port
            tlsClient = new TcpListener(1177);

            // Start the TCP listener and listen for connections
            tlsClient.Start();


            // The while loop will check for true in this before checking for connections
            ServRunning = true;

            // Start the new tread that hosts the listener
            thrListener = new Thread(KeepListening);
            thrListener.Start();
        }

        public void CloseListening()
        {
            //thrListener.Abort();
            tlsClient.Stop();
            ServRunning = false;
        }



        private void KeepListening()
        {
            // While the server is running
            while (ServRunning == true)
            {
                // Accept a pending connection
                tcpClient = tlsClient.AcceptTcpClient();
                // Create a new instance of Connection
                Connection newConnection = new Connection(tcpClient);
            }
        }
    }

    // This class handels connections; there will be as many instances of it as there will be connected users
    public class Connection
    {
        TcpClient tcpClient;
        // The thread that will send information to the client
        private Thread thrSender;
        private StreamReader srReceiver;
        private StreamWriter swSender;
        private string currUser;
        private string strResponse;

        // The constructor of the class takes in a TCP connection
        public Connection(TcpClient tcpCon)
        {
            tcpClient = tcpCon;
            // The thread that accepts the client and awaits messages
            thrSender = new Thread(AcceptClient);
            // The thread calls the AcceptClient() method
            thrSender.Start();
        }

        public void CloseConnection()
        {
            // Close the currently open objects
            tcpClient.Close();
            srReceiver.Close();
            swSender.Close();
        }

        // Occures when a new client is accepted
        private void AcceptClient()
        {
            srReceiver = new System.IO.StreamReader(tcpClient.GetStream());
            swSender = new System.IO.StreamWriter(tcpClient.GetStream());

            // Read the account information from the client
            currUser = srReceiver.ReadLine();

            // We got a response from the client
            if (currUser != "")
            {
                // Store the user name in the hash table
                if (ChatServer.htUsers.Contains(currUser) == true)
                {
                    // 0 means not connected
                    swSender.WriteLine("0|This username already exists.");
                    swSender.Flush();
                    CloseConnection();
                    return;
                }
                else if (currUser == "Administrator")
                {
                    // 0 means not connected
                    swSender.WriteLine("0|This username is reserved.");
                    swSender.Flush();
                    CloseConnection();
                    return;
                }
                else
                {
                    // 1 means connected successfully
                    swSender.WriteLine("1");
                    swSender.Flush();

                    // Add the user to the hash tables and start listening for messages from him
                    ChatServer.AddUser(tcpClient, currUser);
                }
            }
            else
            {
                CloseConnection();
                return;
            }

            try
            {
                // Keep waiting for a message from the user
                while ((strResponse = srReceiver.ReadLine()) != "")
                {
                    // If it's invalid, remove the user
                    if (strResponse == null)
                    {
                        ChatServer.RemoveUser(tcpClient);
                    }
                    else
                    {
                        // Otherwise send the message to all the other users
                        ChatServer.SendMessage(currUser, strResponse);
                    }
                }
            }
            catch
            {
                // If anything went wrong with this user, disconnect him
                ChatServer.RemoveUser(tcpClient);
            }
        }
    }
}

1 answer

1


Problem solved by one break; here

private void KeepListening()
{
    // While the server is running
    while (ServRunning == true)
    {
        // Accept a pending connection
        tcpClient = tlsClient.AcceptTcpClient();
        // Create a new instance of Connection
        Connection newConnection = new Connection(tcpClient);
        break;
    }
}

and here

private void Chat_FormClosed(object sender, FormClosedEventArgs e)
{

    // CloseConnection("Disconectado.");
    Connection con = new Connection(tcpServer);
    con.CloseConnection();
    this.Hide();
}

change this

   // CloseConnection("Disconectado.");
    Connection con = new Connection(tcpServer);
    con.CloseConnection();

for this reason CloseConnection("Disconectado.");

  • 1

    It has nothing to do, but it is "disconnected" that is written. Be careful with your writing, use an automatic corrector that will surely help you.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.