聊天客户端在客户端断开连接时崩溃

本文关键字:客户端 崩溃 连接 断开 聊天 | 更新日期: 2023-09-27 17:56:28

我一直在按照一个旧教程制作聊天程序,我一直在剖析它以适应新形式,尽管我已经让它按预期工作,但它遇到了错误:"无法从传输连接读取数据:阻塞操作被调用 WSACancelBlockingCall 中断。

这指向代码的这一部分。

        while (Connected)
        {
            // Show the messages in the log TextBox
            this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
        }

我仅在关闭客户端或断开连接时收到错误。

这是大多数客户端代码。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.IO;
namespace Table_Top_RPG
{
    public partial class Connect : Form
    {
        // Will hold the user name
        private string UserName = "Unknown";
        public static StreamWriter swSender;
        private StreamReader srReceiver;
        private TcpClient tcpServer;
        // Needed to update the form with messages from another thread
        private delegate void UpdateLogCallback(string strMessage);
        // Needed to set the form to a "disconnected" state from another thread
        private delegate void CloseConnectionCallback(string strReason);
        private Thread thrMessaging;
        private IPAddress ipAddr;
        private bool Connected;
        public Connect()
        {
            // On application exit, don't forget to disconnect first
            Application.ApplicationExit += new EventHandler(OnApplicationExit);
            InitializeComponent();
        }
        private void BtnConnect_Click(object sender, EventArgs e)
        {
            // If we are not currently connected but awaiting to connect
            if (Connected == false)
            {
                InitializeConnection();
            }
            else // We are connected, thus disconnect
            {
                CloseConnection("Disconnected at user's request.");
            }
        }
        // The event handler for application exit
        public void OnApplicationExit(object sender, EventArgs e)
        {
            if (Connected == true)
            {
                // Closes the connections, streams, etc.
                Connected = false;
                swSender.Close();
                srReceiver.Close();
                tcpServer.Close();
            }
        }
        private void InitializeConnection()
        {
            // Parse the IP address from the TextBox into an IPAddress object
            ipAddr = IPAddress.Parse(Connect.IpBox.Text);
            // Start a new TCP connections to the chat server
            tcpServer = new TcpClient();
            tcpServer.Connect(ipAddr, int.Parse(Connect.PortBox.Text));
            // Helps us track whether we're connected or not
            Connected = true;
            // Prepare the form
            UserName = Connect.NameBox.Text;
            // Disable and enable the appropriate fields
            IpBox.Enabled = false;
            NameBox.Enabled = false;
            Main.TxtMsg.Enabled = true;
            Connect.BtnConnect.Text = "Disconnect";
            // Send the desired username to the server
            swSender = new StreamWriter(tcpServer.GetStream());
            swSender.WriteLine(UserName);
            swSender.Flush();
            // Start the thread for receiving messages and further communication
            thrMessaging = new Thread(new ThreadStart(ReceiveMessages));
            thrMessaging.Start();
        }
        private void ReceiveMessages()
        {
            // Receive the response from the server
            srReceiver = new StreamReader(tcpServer.GetStream());
            // If the first character of the response is 1, connection was successful
            string ConResponse = srReceiver.ReadLine();
            // If the first character is a 1, connection was successful
            if (ConResponse[0] == '1')
            {
                // Update the form to tell it we are now connected
                this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { "Connected Successfully!" });
            }
            else // If the first character is not a 1 (probably a 0), the connection was unsuccessful
            {
                string Reason = "Not Connected: ";
                // Extract the reason out of the response message. The reason starts at the 3rd character
                Reason += ConResponse.Substring(2, ConResponse.Length - 2);
                // Update the form with the reason why we couldn't connect
                this.Invoke(new CloseConnectionCallback(this.CloseConnection), new object[] { Reason });
                // Exit the method
                return;
                }
                // While we are successfully connected, read incoming lines from the server
                while (Connected)
                {
                    // Show the messages in the log TextBox
                    this.Invoke(new UpdateLogCallback(this.UpdateLog), new object[] { srReceiver.ReadLine() });
                }
            }
            internal void CloseConnection(string Reason)
            {
                // Show the reason why the connection is ending
                Main.ChatLog.AppendText(Reason + "'r'n");
                // Enable and disable the appropriate controls on the form
                IpBox.Enabled = true;
                NameBox.Enabled = true;
                Main.TxtMsg.Enabled = false;
                BtnConnect.Text = "Connect";
                // Close the objects
                Connected = false;
                swSender.Close();
                srReceiver.Close();
                tcpServer.Close();
            }
            // This method is called from a different thread in order to update the log TextBox
            private void UpdateLog(string strMessage)
            {
                // Append text also scrolls the TextBox to the bottom each time
                Main.ChatLog.AppendText(strMessage + "'r'n");
            }
        }
    }

还有另一种称为 Main 的表单,其中发送了所有聊天对话框,但其大部分代码都不相关。

如果有人知道更好的方法来处理这个问题,或者知道一个好的聊天程序教程,我可以通过更好的示例来了解如何正确处理客户端连接和断开连接而不会崩溃,我将不胜感激。

聊天客户端在客户端断开连接时崩溃

您可能应该考虑使用异步编程,其中没有阻塞调用。问题是,正如您肯定知道的那样,您在有活动呼叫时关闭客户端。

我很确定NetworkStream和StreamReader/Writer确实有一些异步方法。尝试在这里查看一些:http://msdn.microsoft.com/en-us/library/system.io.streamreader.readasync.aspx

我相信

您需要关闭并处置每次使用中的每个流,因为您正在同步执行它们。 考虑使用 using 语句编写...并做类似的事情来阅读。 另外,不要忘记将它们从CloseConnection中删除...

using (NetworkStream ns=tcpServer.GetStream())
{
    swSender = new StreamWriter(ns);
    swSender.WriteLine(UserName);
    swSender.Flush();
    ns.Close();
    ns.Dispose();
    swSender = null;
}