Как исправить ошибку при отключении клиента от сервера - C#

Узнай цену своей работы

Формулировка задачи:

Доброго времени суток гос-да программисты. Есть примеры кода клиент-сервер. Всё работает, но при отключении клиента ("Стоп") или даже просто при закрытии окна чата, выходит ошибка (скрин прикреплён). После трёх дней безуспешных попыток исправить самостоятельно, решил создать эту тему, а вдруг есть на свете такие люди, которые умеют исправлять такое клиент :
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 ChatClient
{
    public partial class Form1 : Form
    {
        // Будет хранить имя пользователя
        private string UserName = "Unknown";
        private StreamWriter swSender;
        private StreamReader srReceiver;
        private TcpClient tcpServer;
        // Необходимо обновить форму с сообщениями из другого потокаd
        private delegate void UpdateLogCallback(string strMessage);
        // Необходимо установить форму в "отключенном" состоянии из другого потока
        private delegate void CloseConnectionCallback(string strReason);
        private Thread thrMessaging;
        private IPAddress ipAddr;
        private bool Connected;
 
        public Form1()
        {
            // На выходе из приложения, не забудьте отключить первый
            Application.ApplicationExit += new EventHandler(OnApplicationExit);
            InitializeComponent();
        }
 
        // Обработчик события для выхода из приложения
        public void OnApplicationExit(object sender, EventArgs e)
        {
            if (Connected == true)
            {
                // Закрывает соединения, потоки, и т.д.
                Connected = false;
                swSender.Close();
                srReceiver.Close();
                tcpServer.Close();
            }
        }
 
        private void btnConnect_Click(object sender, EventArgs e)
        {
            // Если мы сейчас не подключены, но в ожидании подключения
            if (Connected == false)
            {
                // Инициализация связи
                InitializeConnection();
            }
            else // Мы связаны, таким образом, отсоедините
            {
                CloseConnection("Disconnected at user's request.");
            }
        }
 
        private void InitializeConnection()
        {
            // Разбор IP-адреса из TextBox в IP-адрес объекта
            ipAddr = IPAddress.Parse(txtIp.Text);
            // Начало нового соединения TCP для чат-сервера
            tcpServer = new TcpClient();
            tcpServer.Connect(ipAddr, 1986);
 
            // Помогает нам отслеживать ли мы связаны или нет
            Connected = true;
            // Prepare the form
            UserName = txtUser.Text;
 
            // Отключить и включить в соответствующие поля
            txtIp.Enabled = false;
            txtUser.Enabled = false;
            txtMessage.Enabled = true;
            btnSend.Enabled = true;
            btnConnect.Text = "Стоп";
 
            // Отправить желаемое имя пользователя на сервере
            swSender = new StreamWriter(tcpServer.GetStream());
            swSender.WriteLine(txtUser.Text);
            swSender.Flush();
 
            // Начало нити для получения сообщений и дальнейшее общение
            thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
            thrMessaging.Start();
        }
 
        private void ReceiveMessages()
        {
            // Получить ответ от сервера
            srReceiver = new StreamReader(tcpServer.GetStream());
            // Если первый символ в ответ равен 1, соединение было успешным
            string ConResponse = srReceiver.ReadLine();
            // Если первый символ равен 1, соединение было успешным
            if (ConResponse[0] == '1')
            {
                // Обновите форму, чтобы сказать ему мы теперь связаны
                this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { "Connected Successfully!" });
            }
            else // Если первый символ не является 1 (возможно, 0), связь была неудачной
            {
                string Reason = "Not Connected: ";
                // Извлечение причине из ответного сообщения.Причина начинается с 3-го символа
                Reason += ConResponse.Substring(2, ConResponse.Length - 2);
                // Обновление формы с причиной, почему мы не могли соединиться
                this.Invoke(new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });
                // Выход из метода
                return;
            }
            // Пока мы успешно подключились, читать входящие линии с сервера
            while (Connected)
            {
                // Показать сообщения в журнале TextBox
                this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
            }
        }
 
        // Этот метод вызывается из другого потока, чтобы обновить журнал TextBox
        private void UpdateLog(string strMessage)
        {
            // Добавить текст также свитки TextBox на дно каждый раз
            txtLog.AppendText(strMessage + "\r\n");
        }
 
        // Закрывает текущее соединение
        private void CloseConnection(string Reason)
        {
            // Показать причине соединение заканчивается
            txtLog.AppendText(Reason + "\r\n");
            // Включить и отключить соответствующие элементы управления на форму
            txtIp.Enabled = true;
            txtUser.Enabled = true;
            txtMessage.Enabled = false;
            btnSend.Enabled = false;
            btnConnect.Text = "Connect";
 
            // Закройте объектов
            Connected = false;
            swSender.Close();
            srReceiver.Close();
            tcpServer.Close();
        }
 
        // Отправка сообщения набрали на сервер
        private void SendMessage()
        {
            if (txtMessage.Lines.Length >= 1)
            {
                swSender.WriteLine(txtMessage.Text);
                swSender.Flush();
                txtMessage.Lines = null;
            }
            txtMessage.Text = "";
        }
 
        // Мы хотим, чтобы отправить сообщение, когда Send нажатии кнопки
        private void btnSend_Click(object sender, EventArgs e)
        {
            SendMessage();
        }
 
        // Но мы также хотим, чтобы отправить сообщение один раз Enter нажат
        private void txtMessage_KeyPress(object sender, KeyPressEventArgs e)
        {
            // Если клавиша Enter
            if (e.KeyChar == (char)13)
            {
                SendMessage();
            }
        }
    }
}
сервер :
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections;
 
namespace ChatServer
{
    // 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 + " says: " + 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(1986);
 
            // 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();
        }
 
        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
    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();
        }
 
        private 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);
            }
        }
    }
}
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;
 
namespace ChatServer
{
    public partial class Form1 : Form
    {
        private delegate void UpdateStatusCallback(string strMessage);
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void btnListen_Click(object sender, EventArgs e)
        {
            // Разбор IP-адрес сервера из TextBox
            IPAddress ipAddr = IPAddress.Parse(txtIp.Text);
            // Создайте новый экземпляр объекта ChatServer
            ChatServer mainServer = new ChatServer(ipAddr);
            // Наденьте StatusChanged обработчик события mainServer_StatusChanged
            ChatServer.StatusChanged += new StatusChangedEventHandler(mainServer_StatusChanged);
            // Начать прослушивание соединений
            mainServer.StartListening();
            // Показать, что мы начали ожидать соединения
            txtLog.AppendText("Monitoring for connections...\r\n");
        }
 
        public void mainServer_StatusChanged(object sender, StatusChangedEventArgs e)
        {
            // Вызовите метод, который обновляет форму
            this.Invoke(new UpdateStatusCallback(this.UpdateStatus), new object[] { e.EventMessage });
        }
 
        private void UpdateStatus(string strMessage)
        {
            // Обновления журнал с сообщением
            txtLog.AppendText(strMessage + "\r\n");
        }
    }
}
Очень прошу помощи в решении этой проблемы.

Решение задачи: «Как исправить ошибку при отключении клиента от сервера»

textual
Листинг программы
while (Connected != 0)
            {
                if (Connected != 0)
                {
                    try
                    {
                        this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
                    }
                    catch (Exception ex)
                    {
                        MessageBox.Show(ex.Message);
                    }
                }
                else
                {
                    break;
                }
                // Показать сообщения в журнале TextBox
                
            }

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

13   голосов , оценка 4.154 из 5
Похожие ответы