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

同期的に実行しているため、使用ごとに各ストリームを閉じて破棄する必要があると思います。書き込みに 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 に答える
0

おそらく、ブロッキング呼び出しがない非同期プログラミングの使用を検討する必要があります。問題は、ご存じのとおり、アクティブな通話中にクライアントを閉じることです。

NetworkStream と StreamReader/Writer にはいくつかの非同期メソッドがあると確信しています。ここでいくつか見てみてください: http://msdn.microsoft.com/en-us/library/system.io.streamreader.readasync.aspx

于 2013-01-29T18:39:40.480 に答える