0

我一直在关注一个制作聊天程序的旧教程,并且我一直在对其进行剖析以适应新形式,尽管我已经让它按预期工作,但它遇到了错误:“无法从传输中读取数据连接:阻塞操作被 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 的表单,其中发送了所有聊天对话框,但其大部分代码不相关。

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

4

2 回答 2

0

您可能应该考虑使用没有阻塞调用的异步编程。正如您肯定知道的那样,问题在于您在通话期间关闭了您的客户端。

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

于 2013-01-29T18:39:40.480 回答
0

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

using (NetworkStream ns=tcpServer.GetStream())
{
    swSender = new StreamWriter(ns);
    swSender.WriteLine(UserName);
    swSender.Flush();
    ns.Close();
    ns.Dispose();
    swSender = null;
}
于 2013-01-29T19:07:19.530 回答