现有连接被远程主机强行关闭

Posted

技术标签:

【中文标题】现有连接被远程主机强行关闭【英文标题】:An existing connection was forcibly closed by remote host 【发布时间】:2019-12-14 19:33:10 【问题描述】:

我的 C# windows 表单的一部分是点对点(只有两个用户)聊天。 我使用.Net Socket。

我想做的是,只要两个用户都有空,他们就可以聊天。但是,当其中一个关闭程序然后再次打开它时,会出现许多问题。或者当只有一个在线时,我会收到此异常。

“一个现有的连接被远程主机强行关闭”。

我尝试使用 Socket.Close 和 Socket.ShutDown。我还尝试通过再次定义套接字变量来重新启动它。一切似乎都不起作用。即使使用不同的库或方法,我也愿意接受任何建议。

代码如下:

namespace TextChatApp

    public partial class Form1 : Form

    
        //attributes:
        Socket sck;
        EndPoint epLocal, epRemote;



        public Form1()
        
            InitializeComponent();
            sck = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            sck.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, true);

            textBox1.Text=GetLocalIP();
            textBox3.Text = GetLocalIP();
            textBox2.Text = "8001";
            textBox4.Text = "8000";
            send.Enabled = false;
            connectEndPoint();
            InitTimer();
        

        private void MessageCallBack(IAsyncResult aResult)
        
            try
            
                int size = sck.EndReceiveFrom(aResult, ref epRemote);
                if(size>0)
                
                    byte[] receivedData = new byte[1500];
                    receivedData = (byte[])aResult.AsyncState;
                    ASCIIEncoding eEncoding = new ASCIIEncoding();
                    string receivedMessage = eEncoding.GetString(receivedData);
                    listBox1.Items.Add("From a friend: "+receivedMessage);
                
                byte[] buffer = new byte[1500];
                sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref epRemote, new AsyncCallback(MessageCallBack), buffer);

            
            catch(Exception exp)
            
                MessageBox.Show("Exception Small Chat: " + exp.ToString());
            
        

        private void start_Click(object sender, EventArgs e)
        

        

        public void connectEndPoint()
        
            try
            
                epLocal = new IPEndPoint(IPAddress.Parse(textBox1.Text), Convert.ToInt32(textBox2.Text));
                sck.Bind(epLocal);

                epRemote = new IPEndPoint(IPAddress.Parse(textBox3.Text), Convert.ToInt32(textBox4.Text));
                sck.Connect(epRemote);

                byte[] buffer = new byte[1500];
                sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, ref epRemote, new AsyncCallback(MessageCallBack), buffer);
                start.Enabled = false;
                start.Text = "Connected";
                send.Enabled = true;
                textBox5.Focus();

            
            catch (Exception exp)
            

            
        

        private void send_Click(object sender, EventArgs e)
        
            try
            
                System.Text.Encoding encoding = System.Text.Encoding.UTF8;
                byte[] msg = new byte[1500];
                msg = encoding.GetBytes(textBox5.Text);//

                sck.Send(msg);
                listBox1.Items.Add("You: " + textBox5.Text);
                textBox5.Clear();
            
            catch(Exception exp)
            
                MessageBox.Show("Exception Small Chat: " + exp.ToString());
            
        

【问题讨论】:

哪一行抛出异常? int size = sck.EndReceiveFrom(aResult, ref epRemote); 抛出的SocketException 应该有一个ErrorCode 属性;是否对应Windows Sockets Error Codes list中的一个,在你不同的场景下,你每次得到的都是一样的吗? 在这个异常之后一切都开始出错了。 0x80004005。当其中一个点发送数据而另一个点因任何原因离线时,就会发生这种情况。为了避免这种情况,我尝试采用不同的方法在发送数据之前检查一个点是否在线。但是,我还没有解决。 【参考方案1】:

我想我解决了自己的问题。 由于我在发送数据时触发了异常并且端点关闭或未连接,因此我应该在发送数据之前检查它是否已连接。

但是,没有直接的方法可以确定端点是否已连接。 因为当我发送数据并且端点关闭时它会触发异常,所以异常成为我的指标,表明端点关闭并且连接丢失。所以我要做的是在“Catch”语句中再次创建 Socket,并每隔一段时间再试一次,直到 Socket 再次连接。

我每次触发异常时都重新创建Socket是因为Socket会不稳定,会导致很多连接问题。所以最好重新创建它而不是不稳定。

这是我包含的代码

               private void MessageCallBack(IAsyncResult aResult)
                  
                 try
                
                    int size = sck.EndReceiveFrom(aResult, ref epRemote);
                    if(size>0)
                    
                        byte[] receivedData = new byte[1500];
                        receivedData = (byte[])aResult.AsyncState;
                        ASCIIEncoding eEncoding = new ASCIIEncoding();
                        string receivedMessage = eEncoding.GetString(receivedData);
                        listBox1.Invoke(new MethodInvoker(delegate  
                    listBox1.Items.Add("From a friend: " + receivedMessage); ));
                    
                    byte[] buffer = new byte[1500];
                    sck.BeginReceiveFrom(buffer, 0, buffer.Length, SocketFlags.None, 
                ref epRemote, new AsyncCallback(MessageCallBack), buffer);

                
                catch(Exception exp)
                 /* here is the solution, when the Catch is triggered, close the 
                  socket and recreate it to avoid the issues that I been having of 
                  not sending messages and instability. I also added some functions 
                  that would keep sending the status and //being checked on the other 
                  side in order to keep online/offline status.*/

                    sck.Close();
                    sck = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, 
                     ProtocolType.Udp);
                    sck.SetSocketOption(SocketOptionLevel.Socket, 
                     SocketOptionName.ReuseAddress, true);
                    connectEndPoint();
                    //MessageBox.Show("Exception Small Chat: " + exp.ToString());
                
    

【讨论】:

以上是关于现有连接被远程主机强行关闭的主要内容,如果未能解决你的问题,请参考以下文章

现有连接被远程主机强行关闭

无法将数据写入传输连接:现有连接被远程主机强行关闭

System.Net.Sockets.SocketException:'现有连接被远程主机强行关闭'

Azure Blob 存储异常“现有连接被远程主机强行关闭”

操作错误:现有连接被远程主机强行关闭。 (10054)

如何正确关闭客户端代理(现有连接被远程主机强行关闭)?