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

时间:2013-01-29 18:27:32

标签: c# client runtime chat disconnect

我一直在关注制作聊天程序的旧教程,我一直在解析它以适应新的形式,虽然我已经让它工作,因为它意图遇到错误:“无法读取数据来自传输连接:通过调用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的表单,其中发送了所有聊天对话框,但其大部分代码都不相关。

如果有人知道一个更好的方法来处理这个或知道一个好的聊天程序教程我可以通过更好的例子来说明如何正确处理客户端连接和断开而不会崩溃我会非常感激。

2 个答案:

答案 0 :(得分:0)

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

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

答案 1 :(得分:0)

我相信您需要关闭并处理每个用户的每个流,因为您正在同步执行它们。考虑使用using语句进行编写......并做一些类似的阅读。另外,不要忘记将它们从CloseConnection中删除......

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